1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * Was originally part of toxine frontend.
21  * ...but has now been adapted to xine coding style standards ;)
22  * ......what changes, impressive!
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pthread.h>
34 
35 #include "xine.h"
36 
37 #include <xine/video_out.h>
38 #include <xine/xine_internal.h>
39 #include <xine/xineutils.h>
40 #include <xine/vo_scale.h>
41 
42 typedef struct {
43   vo_frame_t           vo_frame;
44   unsigned int         width;
45   unsigned int         height;
46   double               ratio;
47   int                  format;
48 } vo_none_frame_t;
49 
50 typedef struct {
51   vo_driver_t          vo_driver;
52   int                  ratio;
53   xine_t               *xine;
54 } vo_none_driver_t;
55 
56 typedef struct {
57   video_driver_class_t  driver_class;
58   xine_t               *xine;
59 } vo_none_class_t;
60 
61 
vo_none_free_framedata(vo_none_frame_t * frame)62 static void vo_none_free_framedata(vo_none_frame_t* frame) {
63   if(frame->vo_frame.base[0]) {
64     xine_free_aligned(frame->vo_frame.base[0]);
65     frame->vo_frame.base[0] = NULL;
66     frame->vo_frame.base[1] = NULL;
67     frame->vo_frame.base[2] = NULL;
68   }
69 }
70 
vo_none_frame_dispose(vo_frame_t * vo_frame)71 static void vo_none_frame_dispose(vo_frame_t *vo_frame) {
72   vo_none_frame_t *frame = (vo_none_frame_t *)vo_frame;
73   vo_none_free_framedata(frame);
74   pthread_mutex_destroy (&frame->vo_frame.mutex);
75   free (frame);
76 }
77 
vo_none_frame_field(vo_frame_t * vo_frame,int which_field)78 static void vo_none_frame_field(vo_frame_t *vo_frame, int which_field) {
79   /* do nothing */
80   (void)vo_frame;
81   (void)which_field;
82 }
83 
vo_none_get_capabilities(vo_driver_t * vo_driver)84 static uint32_t vo_none_get_capabilities(vo_driver_t *vo_driver) {
85   /* No, we dont crop. Neither do we interpret color matrix or range. */
86   /* But we also dont ask decoders to convert data just for the trash ;-) */
87   (void)vo_driver;
88   return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_COLOR_MATRIX | VO_CAP_FULLRANGE;
89 }
90 
vo_none_alloc_frame(vo_driver_t * vo_driver)91 static vo_frame_t *vo_none_alloc_frame(vo_driver_t *vo_driver) {
92   /* none_driver_t *this = (none_driver_t *) vo_driver; */
93   vo_none_frame_t  *frame;
94 
95   frame = calloc(1, sizeof(vo_none_frame_t));
96   if(!frame)
97     return NULL;
98 
99   pthread_mutex_init(&frame->vo_frame.mutex, NULL);
100 
101   frame->vo_frame.base[0] = NULL;
102   frame->vo_frame.base[1] = NULL;
103   frame->vo_frame.base[2] = NULL;
104 
105   frame->vo_frame.proc_slice = NULL;
106   frame->vo_frame.proc_frame = NULL;
107   frame->vo_frame.field      = vo_none_frame_field;
108   frame->vo_frame.dispose    = vo_none_frame_dispose;
109   frame->vo_frame.driver     = vo_driver;
110 
111   return (vo_frame_t *)frame;
112 }
113 
vo_none_update_frame_format(vo_driver_t * vo_driver,vo_frame_t * vo_frame,uint32_t width,uint32_t height,double ratio,int format,int flags)114 static void vo_none_update_frame_format(vo_driver_t *vo_driver, vo_frame_t *vo_frame,
115 				     uint32_t width, uint32_t height,
116 				     double ratio, int format, int flags) {
117   vo_none_driver_t *this = (vo_none_driver_t *) vo_driver;
118   vo_none_frame_t  *frame = (vo_none_frame_t *) vo_frame;
119 
120   (void)flags;
121   if((frame->width != width) || (frame->height != height) || (frame->format != format)) {
122 
123     vo_none_free_framedata(frame);
124 
125     frame->width  = width;
126     frame->height = height;
127     frame->format = format;
128 
129     switch(format) {
130 
131     case XINE_IMGFMT_YV12:
132       {
133 	int y_size, uv_size;
134 
135 	frame->vo_frame.pitches[0] = 8*((width + 7) / 8);
136 	frame->vo_frame.pitches[1] = 8*((width + 15) / 16);
137 	frame->vo_frame.pitches[2] = 8*((width + 15) / 16);
138 
139 	y_size  = frame->vo_frame.pitches[0] * height;
140 	uv_size = frame->vo_frame.pitches[1] * ((height+1)/2);
141 
142 	frame->vo_frame.base[0] = xine_malloc_aligned (y_size + 2*uv_size);
143         if (frame->vo_frame.base[0]) {
144           frame->vo_frame.base[1] = frame->vo_frame.base[0] + y_size;
145           frame->vo_frame.base[2] = frame->vo_frame.base[0] + y_size + uv_size;
146         } else {
147           frame->vo_frame.base[1] = NULL;
148           frame->vo_frame.base[2] = NULL;
149           xprintf (this->xine, XINE_VERBOSITY_DEBUG,
150             "video_out_none: error. (framedata allocation failed: out of memory)\n");
151           frame->width = 0;
152           frame->vo_frame.width = 0;
153         }
154       }
155       break;
156 
157     case XINE_IMGFMT_YUY2:
158       frame->vo_frame.pitches[0] = 8*((width + 3) / 4);
159       frame->vo_frame.base[0] = xine_malloc_aligned(frame->vo_frame.pitches[0] * height);
160       frame->vo_frame.base[1] = NULL;
161       frame->vo_frame.base[2] = NULL;
162       if (!frame->vo_frame.base[0]) {
163         xprintf (this->xine, XINE_VERBOSITY_DEBUG,
164           "video_out_none: error. (framedata allocation failed: out of memory)\n");
165         frame->width = 0;
166         frame->vo_frame.width = 0;
167       }
168       break;
169 
170     default:
171       xprintf (this->xine, XINE_VERBOSITY_DEBUG, "video_out_none: unknown frame format %04x)\n", format);
172       frame->width = 0;
173       frame->vo_frame.width = 0;
174       break;
175     }
176   }
177 
178   frame->ratio = ratio;
179 }
180 
vo_none_display_frame(vo_driver_t * vo_driver,vo_frame_t * vo_frame)181 static void vo_none_display_frame(vo_driver_t *vo_driver, vo_frame_t *vo_frame) {
182   /* vo_none_driver_t  *driver = (vo_none_driver_t *)vo_driver; */
183 
184   (void)vo_driver;
185   vo_frame->free(vo_frame);
186 }
187 
vo_none_get_property(vo_driver_t * vo_driver,int property)188 static int vo_none_get_property(vo_driver_t *vo_driver, int property) {
189   vo_none_driver_t  *driver = (vo_none_driver_t *)vo_driver;
190 
191   switch(property) {
192 
193   case VO_PROP_ASPECT_RATIO:
194     return driver->ratio;
195     break;
196 
197   default:
198     break;
199   }
200 
201   return 0;
202 }
203 
vo_none_set_property(vo_driver_t * vo_driver,int property,int value)204 static int vo_none_set_property(vo_driver_t *vo_driver, int property, int value) {
205   vo_none_driver_t  *driver = (vo_none_driver_t *)vo_driver;
206 
207   switch(property) {
208 
209   case VO_PROP_ASPECT_RATIO:
210     if(value >= XINE_VO_ASPECT_NUM_RATIOS)
211       value = XINE_VO_ASPECT_AUTO;
212 
213     driver->ratio = value;
214     break;
215 
216   default:
217     break;
218   }
219   return value;
220 }
221 
vo_none_get_property_min_max(vo_driver_t * vo_driver,int property,int * min,int * max)222 static void vo_none_get_property_min_max(vo_driver_t *vo_driver,
223 				      int property, int *min, int *max) {
224   (void)vo_driver;
225   (void)property;
226   *min = 0;
227   *max = 0;
228 }
229 
vo_none_gui_data_exchange(vo_driver_t * vo_driver,int data_type,void * data)230 static int vo_none_gui_data_exchange(vo_driver_t *vo_driver, int data_type, void *data) {
231 /*   vo_none_driver_t     *this = (vo_none_driver_t *) vo_driver; */
232 
233   (void)vo_driver;
234   (void)data;
235   switch (data_type) {
236   case XINE_GUI_SEND_COMPLETION_EVENT:
237   case XINE_GUI_SEND_DRAWABLE_CHANGED:
238   case XINE_GUI_SEND_EXPOSE_EVENT:
239   case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
240   case XINE_GUI_SEND_VIDEOWIN_VISIBLE:
241   case XINE_GUI_SEND_SELECT_VISUAL:
242     break;
243   }
244 
245   return 0;
246 }
vo_none_dispose(vo_driver_t * vo_driver)247 static void vo_none_dispose(vo_driver_t *vo_driver) {
248   vo_none_driver_t *this = (vo_none_driver_t *) vo_driver;
249 
250   free(this);
251 }
252 
vo_none_redraw_needed(vo_driver_t * vo_driver)253 static int vo_none_redraw_needed(vo_driver_t *vo_driver) {
254   (void)vo_driver;
255   return 0;
256 }
257 
vo_none_open_plugin(video_driver_class_t * driver_class,const void * visual)258 static vo_driver_t *vo_none_open_plugin(video_driver_class_t *driver_class, const void *visual) {
259   vo_none_class_t    *class = (vo_none_class_t *) driver_class;
260   vo_none_driver_t   *driver;
261 
262   (void)visual;
263   driver = calloc(1, sizeof(vo_none_driver_t));
264   if (!driver)
265     return NULL;
266 
267   driver->xine   = class->xine;
268   driver->ratio  = XINE_VO_ASPECT_AUTO;
269 
270   driver->vo_driver.get_capabilities     = vo_none_get_capabilities;
271   driver->vo_driver.alloc_frame          = vo_none_alloc_frame ;
272   driver->vo_driver.update_frame_format  = vo_none_update_frame_format;
273   driver->vo_driver.overlay_begin        = NULL;
274   driver->vo_driver.overlay_blend        = NULL;
275   driver->vo_driver.overlay_end          = NULL;
276   driver->vo_driver.display_frame        = vo_none_display_frame;
277   driver->vo_driver.get_property         = vo_none_get_property;
278   driver->vo_driver.set_property         = vo_none_set_property;
279   driver->vo_driver.get_property_min_max = vo_none_get_property_min_max;
280   driver->vo_driver.gui_data_exchange    = vo_none_gui_data_exchange;
281   driver->vo_driver.dispose              = vo_none_dispose;
282   driver->vo_driver.redraw_needed        = vo_none_redraw_needed;
283 
284   return &driver->vo_driver;
285 }
286 
287 /*
288  * Class related functions.
289  */
vo_none_init_class(xine_t * xine,const void * visual)290 static void *vo_none_init_class (xine_t *xine, const void *visual) {
291   vo_none_class_t        *this;
292 
293   (void)visual;
294   this = calloc(1, sizeof(vo_none_class_t));
295   if (!this)
296     return NULL;
297 
298   this->driver_class.open_plugin     = vo_none_open_plugin;
299   this->driver_class.identifier      = "none";
300   this->driver_class.description     = N_("xine video output plugin which displays nothing");
301   this->driver_class.dispose         = default_video_driver_class_dispose;
302 
303   this->xine                         = xine;
304 
305   return this;
306 }
307 
308 static const vo_info_t vo_info_none = {
309   .priority    = 5,
310   .visual_type = XINE_VISUAL_TYPE_NONE,
311 };
312 
313 #define VO_NONE_CATALOG { PLUGIN_VIDEO_OUT, 22, "none", XINE_VERSION_CODE, &vo_info_none, vo_none_init_class }
314 
315 #ifndef XINE_MAKE_BUILTINS
316 const plugin_info_t xine_plugin_info[] EXPORTED = {
317   /* type, API, "name", version, special_info, init_function */
318   VO_NONE_CATALOG,
319   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
320 };
321 #endif
322 
323 
324