]> git.sesse.net Git - vlc/blob - modules/video_filter/transform.c
Fix another bunch of: (near initialization for `fmt.i_aspect') warnings.
[vlc] / modules / video_filter / transform.c
1 /*****************************************************************************
2  * transform.c : transform image module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_vout.h>
32
33 #include "filter_common.h"
34
35 #define TRANSFORM_MODE_HFLIP   1
36 #define TRANSFORM_MODE_VFLIP   2
37 #define TRANSFORM_MODE_90      3
38 #define TRANSFORM_MODE_180     4
39 #define TRANSFORM_MODE_270     5
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44 static int  Create    ( vlc_object_t * );
45 static void Destroy   ( vlc_object_t * );
46
47 static int  Init      ( vout_thread_t * );
48 static void End       ( vout_thread_t * );
49 static void Render    ( vout_thread_t *, picture_t * );
50
51 static int  SendEvents( vlc_object_t *, char const *,
52                         vlc_value_t, vlc_value_t, void * );
53
54 /*****************************************************************************
55  * Module descriptor
56  *****************************************************************************/
57 #define TYPE_TEXT N_("Transform type")
58 #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
59
60 static const char *type_list[] = { "90", "180", "270", "hflip", "vflip" };
61 static const char *type_list_text[] = { N_("Rotate by 90 degrees"),
62   N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
63   N_("Flip horizontally"), N_("Flip vertically") };
64
65 #define CFG_PREFIX "transform-"
66
67 vlc_module_begin();
68     set_description( _("Video transformation filter") );
69     set_shortname( _("Transformation"));
70     set_capability( "video filter", 0 );
71     set_category( CAT_VIDEO );
72     set_subcategory( SUBCAT_VIDEO_VFILTER );
73
74     add_string( CFG_PREFIX "type", "90", NULL,
75                           TYPE_TEXT, TYPE_LONGTEXT, VLC_FALSE);
76         change_string_list( type_list, type_list_text, 0);
77
78     add_shortcut( "transform" );
79     set_callbacks( Create, Destroy );
80 vlc_module_end();
81
82 static const char *ppsz_filter_options[] = {
83     "type", NULL
84 };
85
86 /*****************************************************************************
87  * vout_sys_t: Transform video output method descriptor
88  *****************************************************************************
89  * This structure is part of the video output thread descriptor.
90  * It describes the Transform specific properties of an output thread.
91  *****************************************************************************/
92 struct vout_sys_t
93 {
94     int i_mode;
95     vlc_bool_t b_rotation;
96     vout_thread_t *p_vout;
97 };
98
99 /*****************************************************************************
100  * Control: control facility for the vout (forwards to child vout)
101  *****************************************************************************/
102 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
103 {
104     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
105 }
106
107 /*****************************************************************************
108  * Create: allocates Transform video thread output method
109  *****************************************************************************
110  * This function allocates and initializes a Transform vout method.
111  *****************************************************************************/
112 static int Create( vlc_object_t *p_this )
113 {
114     vout_thread_t *p_vout = (vout_thread_t *)p_this;
115     char *psz_method;
116
117     /* Allocate structure */
118     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
119     if( p_vout->p_sys == NULL )
120     {
121         msg_Err( p_vout, "out of memory" );
122         return VLC_ENOMEM;
123     }
124
125     p_vout->pf_init = Init;
126     p_vout->pf_end = End;
127     p_vout->pf_manage = NULL;
128     p_vout->pf_render = Render;
129     p_vout->pf_display = NULL;
130     p_vout->pf_control = Control;
131
132     config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
133                            p_vout->p_cfg );
134
135     /* Look what method was requested */
136     psz_method = var_CreateGetNonEmptyString( p_vout, "transform-type" );
137
138     if( psz_method == NULL )
139     {
140         msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
141         msg_Err( p_vout, "no valid transform mode provided, using '90'" );
142         p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
143         p_vout->p_sys->b_rotation = 1;
144     }
145     else
146     {
147         if( !strcmp( psz_method, "hflip" ) )
148         {
149             p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
150             p_vout->p_sys->b_rotation = 0;
151         }
152         else if( !strcmp( psz_method, "vflip" ) )
153         {
154             p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
155             p_vout->p_sys->b_rotation = 0;
156         }
157         else if( !strcmp( psz_method, "90" ) )
158         {
159             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
160             p_vout->p_sys->b_rotation = 1;
161         }
162         else if( !strcmp( psz_method, "180" ) )
163         {
164             p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
165             p_vout->p_sys->b_rotation = 0;
166         }
167         else if( !strcmp( psz_method, "270" ) )
168         {
169             p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
170             p_vout->p_sys->b_rotation = 1;
171         }
172         else
173         {
174             msg_Err( p_vout, "no valid transform mode provided, using '90'" );
175             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
176             p_vout->p_sys->b_rotation = 1;
177         }
178
179         free( psz_method );
180     }
181
182     return VLC_SUCCESS;
183 }
184
185 /*****************************************************************************
186  * Init: initialize Transform video thread output method
187  *****************************************************************************/
188 static int Init( vout_thread_t *p_vout )
189 {
190     int i_index;
191     picture_t *p_pic;
192     video_format_t fmt;
193
194     I_OUTPUTPICTURES = 0;
195     memset( &fmt, 0, sizeof(video_format_t) );
196
197     /* Initialize the output structure */
198     p_vout->output.i_chroma = p_vout->render.i_chroma;
199     p_vout->output.i_width  = p_vout->render.i_width;
200     p_vout->output.i_height = p_vout->render.i_height;
201     p_vout->output.i_aspect = p_vout->render.i_aspect;
202     p_vout->fmt_out = p_vout->fmt_in;
203     fmt = p_vout->fmt_out;
204
205     /* Try to open the real video output */
206     msg_Dbg( p_vout, "spawning the real video output" );
207
208     if( p_vout->p_sys->b_rotation )
209     {
210         fmt.i_width = p_vout->fmt_out.i_height;
211         fmt.i_visible_width = p_vout->fmt_out.i_visible_height;
212         fmt.i_x_offset = p_vout->fmt_out.i_y_offset;
213
214         fmt.i_height = p_vout->fmt_out.i_width;
215         fmt.i_visible_height = p_vout->fmt_out.i_visible_width;
216         fmt.i_y_offset = p_vout->fmt_out.i_x_offset;
217
218         fmt.i_aspect = VOUT_ASPECT_FACTOR *
219             (uint64_t)VOUT_ASPECT_FACTOR / fmt.i_aspect;
220
221         fmt.i_sar_num = p_vout->fmt_out.i_sar_den;
222         fmt.i_sar_den = p_vout->fmt_out.i_sar_num;
223     }
224
225     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
226
227     /* Everything failed */
228     if( p_vout->p_sys->p_vout == NULL )
229     {
230         msg_Err( p_vout, "cannot open vout, aborting" );
231         return VLC_EGENERIC;
232     }
233
234     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
235
236     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
237
238     ADD_PARENT_CALLBACKS( SendEventsToChild );
239
240     return VLC_SUCCESS;
241 }
242
243 /*****************************************************************************
244  * End: terminate Transform video thread output method
245  *****************************************************************************/
246 static void End( vout_thread_t *p_vout )
247 {
248     int i_index;
249
250     /* Free the fake output buffers we allocated */
251     for( i_index = I_OUTPUTPICTURES ; i_index ; )
252     {
253         i_index--;
254         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
255     }
256 }
257
258 /*****************************************************************************
259  * Destroy: destroy Transform video thread output method
260  *****************************************************************************
261  * Terminate an output method created by TransformCreateOutputMethod
262  *****************************************************************************/
263 static void Destroy( vlc_object_t *p_this )
264 {
265     vout_thread_t *p_vout = (vout_thread_t *)p_this;
266
267     if( p_vout->p_sys->p_vout )
268     {
269         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
270         vlc_object_detach( p_vout->p_sys->p_vout );
271         vout_Destroy( p_vout->p_sys->p_vout );
272     }
273
274     DEL_PARENT_CALLBACKS( SendEventsToChild );
275
276     free( p_vout->p_sys );
277 }
278
279 /*****************************************************************************
280  * Render: displays previously rendered output
281  *****************************************************************************
282  * This function send the currently rendered image to Transform image, waits
283  * until it is displayed and switch the two rendering buffers, preparing next
284  * frame.
285  *****************************************************************************/
286 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
287 {
288     picture_t *p_outpic;
289     int i_index;
290
291     /* This is a new frame. Get a structure from the video_output. */
292     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
293               == NULL )
294     {
295         if( p_vout->b_die || p_vout->b_error )
296         {
297             return;
298         }
299         msleep( VOUT_OUTMEM_SLEEP );
300     }
301
302     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
303     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
304
305     switch( p_vout->p_sys->i_mode )
306     {
307         case TRANSFORM_MODE_90:
308             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
309             {
310                 int i_pitch = p_pic->p[i_index].i_pitch;
311
312                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
313
314                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
315                 uint8_t *p_out_end = p_out +
316                     p_outpic->p[i_index].i_visible_lines *
317                     p_outpic->p[i_index].i_pitch;
318
319                 for( ; p_out < p_out_end ; )
320                 {
321                     uint8_t *p_line_end;
322
323                     p_out_end -= p_outpic->p[i_index].i_pitch
324                                   - p_outpic->p[i_index].i_visible_pitch;
325                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
326                         i_pitch;
327
328                     for( ; p_in < p_line_end ; )
329                     {
330                         p_line_end -= i_pitch;
331                         *(--p_out_end) = *p_line_end;
332                     }
333
334                     p_in++;
335                 }
336             }
337             break;
338
339         case TRANSFORM_MODE_180:
340             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
341             {
342                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
343                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
344                                             * p_pic->p[i_index].i_pitch;
345
346                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
347
348                 for( ; p_in < p_in_end ; )
349                 {
350                     uint8_t *p_line_start = p_in_end
351                                              - p_pic->p[i_index].i_pitch;
352                     p_in_end -= p_pic->p[i_index].i_pitch
353                                  - p_pic->p[i_index].i_visible_pitch;
354
355                     for( ; p_line_start < p_in_end ; )
356                     {
357                         *p_out++ = *(--p_in_end);
358                     }
359
360                     p_out += p_outpic->p[i_index].i_pitch
361                               - p_outpic->p[i_index].i_visible_pitch;
362                 }
363             }
364             break;
365
366         case TRANSFORM_MODE_270:
367             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
368             {
369                 int i_pitch = p_pic->p[i_index].i_pitch;
370
371                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
372
373                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
374                 uint8_t *p_out_end = p_out +
375                     p_outpic->p[i_index].i_visible_lines *
376                     p_outpic->p[i_index].i_pitch;
377
378                 for( ; p_out < p_out_end ; )
379                 {
380                     uint8_t *p_in_end;
381
382                     p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
383                         i_pitch;
384
385                     for( ; p_in < p_in_end ; )
386                     {
387                         p_in_end -= i_pitch;
388                         *p_out++ = *p_in_end;
389                     }
390
391                     p_out += p_outpic->p[i_index].i_pitch
392                               - p_outpic->p[i_index].i_visible_pitch;
393                     p_in++;
394                 }
395             }
396             break;
397
398         case TRANSFORM_MODE_HFLIP:
399             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
400             {
401                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
402                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
403                                             * p_pic->p[i_index].i_pitch;
404
405                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
406
407                 for( ; p_in < p_in_end ; )
408                 {
409                     p_in_end -= p_pic->p[i_index].i_pitch;
410                     p_vout->p_libvlc->pf_memcpy( p_out, p_in_end,
411                                            p_pic->p[i_index].i_visible_pitch );
412                     p_out += p_pic->p[i_index].i_pitch;
413                 }
414             }
415             break;
416
417         case TRANSFORM_MODE_VFLIP:
418             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
419             {
420                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
421                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
422                                             * p_pic->p[i_index].i_pitch;
423
424                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
425
426                 for( ; p_in < p_in_end ; )
427                 {
428                     uint8_t *p_line_end = p_in
429                                            + p_pic->p[i_index].i_visible_pitch;
430
431                     for( ; p_in < p_line_end ; )
432                     {
433                         *p_out++ = *(--p_line_end);
434                     }
435
436                     p_in += p_pic->p[i_index].i_pitch;
437                 }
438             }
439             break;
440
441         default:
442             break;
443     }
444
445     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
446
447     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
448 }
449
450 /*****************************************************************************
451  * SendEvents: forward mouse and keyboard events to the parent p_vout
452  *****************************************************************************/
453 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
454                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
455 {
456     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
457     vlc_value_t sentval = newval;
458
459     /* Translate the mouse coordinates */
460     if( !strcmp( psz_var, "mouse-x" ) )
461     {
462         switch( p_vout->p_sys->i_mode )
463         {
464         case TRANSFORM_MODE_270:
465             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
466                              - sentval.i_int;
467         case TRANSFORM_MODE_90:
468             var_Set( p_vout, "mouse-y", sentval );
469             return VLC_SUCCESS;
470
471         case TRANSFORM_MODE_180:
472         case TRANSFORM_MODE_HFLIP:
473             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
474                              - sentval.i_int;
475             break;
476
477         case TRANSFORM_MODE_VFLIP:
478         default:
479             break;
480         }
481     }
482     else if( !strcmp( psz_var, "mouse-y" ) )
483     {
484         switch( p_vout->p_sys->i_mode )
485         {
486         case TRANSFORM_MODE_90:
487             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
488                              - sentval.i_int;
489         case TRANSFORM_MODE_270:
490             var_Set( p_vout, "mouse-x", sentval );
491             return VLC_SUCCESS;
492
493         case TRANSFORM_MODE_180:
494         case TRANSFORM_MODE_VFLIP:
495             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
496                              - sentval.i_int;
497             break;
498
499         case TRANSFORM_MODE_HFLIP:
500         default:
501             break;
502         }
503     }
504
505     var_Set( p_vout, psz_var, sentval );
506
507     return VLC_SUCCESS;
508 }
509
510 /*****************************************************************************
511  * SendEventsToChild: forward events to the child/children vout
512  *****************************************************************************/
513 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
514                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
515 {
516     vout_thread_t *p_vout = (vout_thread_t *)p_this;
517     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
518     return VLC_SUCCESS;
519 }