1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <string.h>
23 #include <x11/x11.h>
24 #include <x11/x11_window_private.h>
25
26 #include <gmerlin/log.h>
27 #define LOG_DOMAIN "x11_video"
28
29 static video_driver_t const * const drivers[] =
30 {
31 &ximage_driver,
32 #ifdef HAVE_LIBXV
33 &xv_driver,
34 #endif
35 #ifdef HAVE_GLX
36 &gl_driver,
37 #endif
38 };
39
set_brightness(bg_x11_window_t * w)40 static int set_brightness(bg_x11_window_t * w)
41 {
42 if(w->video_open &&
43 w->current_driver->driver->set_brightness &&
44 (w->current_driver->flags & DRIVER_FLAG_BRIGHTNESS))
45 {
46 w->current_driver->driver->set_brightness(w->current_driver, w->brightness);
47 return 1;
48 }
49 return 0;
50 }
51
bg_x11_window_set_brightness(bg_x11_window_t * w,float val)52 int bg_x11_window_set_brightness(bg_x11_window_t * w, float val)
53 {
54 w->brightness = val;
55 return set_brightness(w);
56 }
57
set_saturation(bg_x11_window_t * w)58 static int set_saturation(bg_x11_window_t * w)
59 {
60 if(w->video_open &&
61 w->current_driver->driver->set_saturation &&
62 (w->current_driver->flags & DRIVER_FLAG_SATURATION))
63 {
64 w->current_driver->driver->set_saturation(w->current_driver, w->saturation);
65 return 1;
66 }
67 return 0;
68 }
69
bg_x11_window_set_saturation(bg_x11_window_t * w,float val)70 int bg_x11_window_set_saturation(bg_x11_window_t * w, float val)
71 {
72 w->saturation = val;
73 return set_saturation(w);
74 }
75
set_contrast(bg_x11_window_t * w)76 static int set_contrast(bg_x11_window_t * w)
77 {
78 if(w->video_open &&
79 w->current_driver->driver->set_contrast &&
80 (w->current_driver->flags & DRIVER_FLAG_CONTRAST))
81 {
82 w->current_driver->driver->set_contrast(w->current_driver, w->contrast);
83 return 1;
84 }
85 return 0;
86 }
87
bg_x11_window_set_contrast(bg_x11_window_t * w,float val)88 int bg_x11_window_set_contrast(bg_x11_window_t * w, float val)
89 {
90 w->contrast = val;
91 return set_contrast(w);
92 }
93
init(bg_x11_window_t * w)94 static void init(bg_x11_window_t * w)
95 {
96 int num_drivers, i;
97 num_drivers = sizeof(drivers) / sizeof(drivers[0]);
98
99 for(i = 0; i < num_drivers; i++)
100 {
101 w->drivers[i].driver = drivers[i];
102 w->drivers[i].win = w;
103 if(w->drivers[i].driver->init)
104 w->drivers[i].driver->init(&w->drivers[i]);
105 }
106
107 /*
108 * Possible TODO: Get screen resolution
109 * (maybe better if we don't care at all)
110 */
111
112 w->window_format.pixel_width = 1;
113 w->window_format.pixel_height = 1;
114 w->idle_counter = 0;
115 }
116
bg_x11_window_cleanup_video(bg_x11_window_t * w)117 void bg_x11_window_cleanup_video(bg_x11_window_t * w)
118 {
119 int num_drivers, i;
120 num_drivers = sizeof(drivers) / sizeof(drivers[0]);
121
122 /* Not initialized */
123 if(!w->drivers[0].driver)
124 return;
125
126 for(i = 0; i < num_drivers; i++)
127 {
128 if(w->drivers[i].driver->cleanup)
129 w->drivers[i].driver->cleanup(&w->drivers[i]);
130 if(w->drivers[i].pixelformats)
131 free(w->drivers[i].pixelformats);
132 }
133 }
134
135
136 /* For Video output */
137
138 #define PAD_SIZE 16
139 #define PAD(sz) (((sz+PAD_SIZE-1) / PAD_SIZE) * PAD_SIZE)
140
bg_x11_window_open_video(bg_x11_window_t * w,gavl_video_format_t * format)141 int bg_x11_window_open_video(bg_x11_window_t * w,
142 gavl_video_format_t * format)
143 {
144 int num_drivers;
145 int i;
146 int force_hw_scale;
147
148 int min_penalty, min_index;
149
150 w->do_sw_scale = 0;
151 w->current_driver = NULL;
152 if(!w->drivers_initialized)
153 {
154 init(w);
155 w->drivers_initialized = 1;
156 }
157
158
159 gavl_video_format_copy(&w->video_format, format);
160
161 /* Pad sizes, which might screw up some drivers */
162
163 w->video_format.frame_width = PAD(w->video_format.frame_width);
164 w->video_format.frame_height = PAD(w->video_format.frame_height);
165
166 if(w->auto_resize)
167 {
168 bg_x11_window_resize(w,
169 (w->video_format.image_width *
170 w->video_format.pixel_width) /
171 w->video_format.pixel_height,
172 w->video_format.image_height);
173 }
174
175 num_drivers = sizeof(drivers) / sizeof(drivers[0]);
176
177 /* Query the best pixelformats for each driver */
178
179 for(i = 0; i < num_drivers; i++)
180 {
181 w->drivers[i].pixelformat =
182 gavl_pixelformat_get_best(format->pixelformat, w->drivers[i].pixelformats,
183 &w->drivers[i].penalty);
184 }
185
186
187 /*
188 * Now, get the driver with the lowest penalty.
189 * Scaling would be nice as well
190 */
191 force_hw_scale = w->force_hw_scale;
192
193 while(1)
194 {
195 min_index = -1;
196 min_penalty = -1;
197
198 /* Find out best driver. Drivers, which don't initialize,
199 have the pixelformat unset */
200 for(i = 0; i < num_drivers; i++)
201 {
202 if(!w->drivers[i].driver->can_scale && force_hw_scale)
203 continue;
204 if(w->drivers[i].pixelformat != GAVL_PIXELFORMAT_NONE)
205 {
206 if((min_penalty < 0) || w->drivers[i].penalty < min_penalty)
207 {
208 min_penalty = w->drivers[i].penalty;
209 min_index = i;
210 }
211 }
212 }
213
214 /* If we have found no driver, playing video is doomed to failure */
215 if(min_penalty < 0)
216 {
217 if(force_hw_scale)
218 {
219 force_hw_scale = 0;
220 continue;
221 }
222 else
223 break;
224 }
225
226
227 if(!w->drivers[min_index].driver->open)
228 {
229 w->current_driver = &w->drivers[min_index];
230 break;
231 }
232 /* Flag as unusable */
233 bg_log(BG_LOG_DEBUG, LOG_DOMAIN, "Trying %s driver",
234 w->drivers[min_index].driver->name);
235 if(!w->drivers[min_index].driver->open(&w->drivers[min_index]))
236 {
237 bg_log(BG_LOG_DEBUG, LOG_DOMAIN, "Opening %s driver failed",
238 w->drivers[min_index].driver->name);
239
240 w->drivers[min_index].pixelformat = GAVL_PIXELFORMAT_NONE;
241 }
242 else
243 {
244 w->current_driver = &w->drivers[min_index];
245 bg_log(BG_LOG_DEBUG, LOG_DOMAIN, "Opening %s driver succeeded",
246 w->drivers[min_index].driver->name);
247 break;
248 }
249 }
250 if(!w->current_driver)
251 return 0;
252
253
254 w->video_format.pixelformat = w->current_driver->pixelformat;
255
256 gavl_video_format_copy(format, &w->video_format);
257
258 /* All other values are already set or will be set by set_rectangles */
259 w->window_format.pixelformat = format->pixelformat;
260
261 if(!w->current_driver->driver->can_scale)
262 {
263 w->do_sw_scale = 1;
264
265 }
266
267 set_contrast(w);
268 set_saturation(w);
269 set_brightness(w);
270
271 XSync(w->dpy, False);
272 bg_x11_window_handle_events(w, 0);
273
274 return 1;
275 }
276
bg_x11_window_create_frame(bg_x11_window_t * w)277 gavl_video_frame_t * bg_x11_window_create_frame(bg_x11_window_t * w)
278 {
279 if(!w->do_sw_scale)
280 {
281 if(w->current_driver->driver->create_frame)
282 return w->current_driver->driver->create_frame(w->current_driver);
283 else
284 return gavl_video_frame_create(&w->video_format);
285 }
286 else
287 return gavl_video_frame_create(&w->video_format);
288 }
289
bg_x11_window_destroy_frame(bg_x11_window_t * w,gavl_video_frame_t * f)290 void bg_x11_window_destroy_frame(bg_x11_window_t * w, gavl_video_frame_t * f)
291 {
292 if(!w->do_sw_scale)
293 {
294 if(w->current_driver->driver->destroy_frame)
295 w->current_driver->driver->destroy_frame(w->current_driver, f);
296 else
297 gavl_video_frame_destroy(f);
298 }
299 else
300 gavl_video_frame_destroy(f);
301 }
302
303 #define PADD_SIZE 128
304 #define PADD_IMAGE_SIZE(s) \
305 s = ((s + PADD_SIZE - 1) / PADD_SIZE) * PADD_SIZE
306
bg_x11_window_set_rectangles(bg_x11_window_t * w,gavl_rectangle_f_t * src_rect,gavl_rectangle_i_t * dst_rect)307 void bg_x11_window_set_rectangles(bg_x11_window_t * w,
308 gavl_rectangle_f_t * src_rect,
309 gavl_rectangle_i_t * dst_rect)
310 {
311 gavl_video_options_t * opt;
312 gavl_rectangle_f_copy(&w->src_rect, src_rect);
313 gavl_rectangle_i_copy(&w->dst_rect, dst_rect);
314
315 if(!w->video_open)
316 w->video_open = 1;
317
318 if(w->current_driver && w->do_sw_scale)
319 {
320
321 if((w->window_format.image_width > w->window_format.frame_width) ||
322 (w->window_format.image_height > w->window_format.frame_height))
323 {
324 w->window_format.frame_width = w->window_format.image_width;
325 w->window_format.frame_height = w->window_format.image_height;
326
327 PADD_IMAGE_SIZE(w->window_format.frame_width);
328 PADD_IMAGE_SIZE(w->window_format.frame_height);
329
330 if(w->window_frame)
331 {
332 if(w->current_driver->driver->destroy_frame)
333 w->current_driver->driver->destroy_frame(w->current_driver,
334 w->window_frame);
335 else
336 gavl_video_frame_destroy(w->window_frame);
337 w->window_frame = NULL;
338 }
339 }
340
341 if(!w->window_frame)
342 {
343 if(w->current_driver->driver->create_frame)
344 w->window_frame = w->current_driver->driver->create_frame(w->current_driver);
345 else
346 w->window_frame = gavl_video_frame_create(&w->window_format);
347 }
348
349 /* Clear window */
350 gavl_video_frame_clear(w->window_frame, &w->window_format);
351
352 /* Reinitialize scaler */
353
354 opt = gavl_video_scaler_get_options(w->scaler);
355 gavl_video_options_set_rectangles(opt, &w->src_rect,
356 &w->dst_rect);
357
358 gavl_video_scaler_init(w->scaler,
359 &w->video_format,
360 &w->window_format);
361 }
362 bg_x11_window_clear(w);
363 }
364
365 #undef PADD_IMAGE_SIZE
366
bg_x11_window_put_frame_internal(bg_x11_window_t * w,gavl_video_frame_t * f)367 void bg_x11_window_put_frame_internal(bg_x11_window_t * w,
368 gavl_video_frame_t * f)
369 {
370
371 if(w->do_sw_scale)
372 {
373 gavl_video_scaler_scale(w->scaler, f, w->window_frame);
374 w->current_driver->driver->put_frame(w->current_driver,
375 w->window_frame);
376 }
377 else
378 w->current_driver->driver->put_frame(w->current_driver, f);
379 }
380
bg_x11_window_put_frame(bg_x11_window_t * w,gavl_video_frame_t * f)381 void bg_x11_window_put_frame(bg_x11_window_t * w, gavl_video_frame_t * f)
382 {
383 w->still_mode = 0;
384 bg_x11_window_put_frame_internal(w, f);
385 }
386
bg_x11_window_put_still(bg_x11_window_t * w,gavl_video_frame_t * f)387 void bg_x11_window_put_still(bg_x11_window_t * w, gavl_video_frame_t * f)
388 {
389 w->still_mode = 1;
390 if(!w->still_frame)
391 {
392 w->still_frame = bg_x11_window_create_frame(w);
393 }
394 gavl_video_frame_copy(&w->video_format, w->still_frame, f);
395 bg_x11_window_put_frame_internal(w, w->still_frame);
396 }
397
398
bg_x11_window_close_video(bg_x11_window_t * w)399 void bg_x11_window_close_video(bg_x11_window_t * w)
400 {
401 if(w->window_frame)
402 {
403 if(w->current_driver->driver->destroy_frame)
404 w->current_driver->driver->destroy_frame(w->current_driver, w->window_frame);
405 else
406 gavl_video_frame_destroy(w->window_frame);
407 w->window_frame = NULL;
408 }
409 if(w->still_frame)
410 {
411 bg_x11_window_destroy_frame(w, w->still_frame);
412 w->still_frame = NULL;
413 }
414
415 if(w->overlay_streams)
416 {
417 free(w->overlay_streams);
418 w->num_overlay_streams = 0;
419 w->overlay_streams = NULL;
420 }
421
422 if(w->current_driver->driver->close)
423 w->current_driver->driver->close(w->current_driver);
424
425 w->video_open = 0;
426
427 XSync(w->dpy, False);
428 bg_x11_window_handle_events(w, 0);
429 }
430
431