]> git.sesse.net Git - vlc/blob - plugins/filter/transform.c
651a3a9bb3a720eb7d37052e070fe1af5fab3343
[vlc] / plugins / filter / transform.c
1 /*****************************************************************************
2  * transform.c : transform image plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: transform.c,v 1.16 2002/07/20 18:01:42 sam Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33
34 #include "filter_common.h"
35
36 #define TRANSFORM_MODE_HFLIP   1
37 #define TRANSFORM_MODE_VFLIP   2
38 #define TRANSFORM_MODE_90      3
39 #define TRANSFORM_MODE_180     4
40 #define TRANSFORM_MODE_270     5
41
42 /*****************************************************************************
43  * Capabilities defined in the other files.
44  *****************************************************************************/
45 static void vout_getfunctions( function_list_t * p_function_list );
46
47 /*****************************************************************************
48  * Build configuration tree.
49  *****************************************************************************/
50 #define TYPE_TEXT N_("Transform type")
51 #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
52
53 static char *type_list[] = { "90", "180", "270", "hflip", "vflip", NULL };
54
55 MODULE_CONFIG_START
56 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
57 ADD_STRING_FROM_LIST("transform-type", "90", type_list, NULL, TYPE_TEXT, TYPE_LONGTEXT)
58 MODULE_CONFIG_STOP
59
60 MODULE_INIT_START
61     SET_DESCRIPTION( _("image transformation module") )
62     /* Capability score set to 0 because we don't want to be spawned
63      * as a video output unless explicitly requested to */
64     ADD_CAPABILITY( VOUT_FILTER, 0 )
65     ADD_SHORTCUT( "transform" )
66 MODULE_INIT_STOP
67
68 MODULE_ACTIVATE_START
69     vout_getfunctions( &p_module->p_functions->vout );
70 MODULE_ACTIVATE_STOP
71
72 MODULE_DEACTIVATE_START
73 MODULE_DEACTIVATE_STOP
74
75 /*****************************************************************************
76  * vout_sys_t: Transform video output method descriptor
77  *****************************************************************************
78  * This structure is part of the video output thread descriptor.
79  * It describes the Transform specific properties of an output thread.
80  *****************************************************************************/
81 struct vout_sys_t
82 {
83     int i_mode;
84     vlc_bool_t b_rotation;
85     vout_thread_t *p_vout;
86 };
87
88 /*****************************************************************************
89  * Local prototypes
90  *****************************************************************************/
91 static int  vout_Create    ( vout_thread_t * );
92 static int  vout_Init      ( vout_thread_t * );
93 static void vout_End       ( vout_thread_t * );
94 static void vout_Destroy   ( vout_thread_t * );
95 static int  vout_Manage    ( vout_thread_t * );
96 static void vout_Render    ( vout_thread_t *, picture_t * );
97 static void vout_Display   ( vout_thread_t *, picture_t * );
98
99 /*****************************************************************************
100  * Functions exported as capabilities. They are declared as static so that
101  * we don't pollute the namespace too much.
102  *****************************************************************************/
103 static void vout_getfunctions( function_list_t * p_function_list )
104 {
105     p_function_list->functions.vout.pf_create     = vout_Create;
106     p_function_list->functions.vout.pf_init       = vout_Init;
107     p_function_list->functions.vout.pf_end        = vout_End;
108     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
109     p_function_list->functions.vout.pf_manage     = vout_Manage;
110     p_function_list->functions.vout.pf_render     = vout_Render;
111     p_function_list->functions.vout.pf_display    = vout_Display;
112 }
113
114 /*****************************************************************************
115  * vout_Create: allocates Transform video thread output method
116  *****************************************************************************
117  * This function allocates and initializes a Transform vout method.
118  *****************************************************************************/
119 static int vout_Create( vout_thread_t *p_vout )
120 {
121     char *psz_method;
122
123     /* Allocate structure */
124     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
125     if( p_vout->p_sys == NULL )
126     {
127         msg_Err( p_vout, "out of memory" );
128         return( 1 );
129     }
130
131     /* Look what method was requested */
132     psz_method = config_GetPsz( p_vout, "transform-type" );
133
134     if( psz_method == NULL )
135     {
136         msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
137         msg_Err( p_vout, "no valid transform mode provided, using '90'" );
138         p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
139         p_vout->p_sys->b_rotation = 1;
140     }
141     else
142     {
143         if( !strcmp( psz_method, "hflip" ) )
144         {
145             p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
146             p_vout->p_sys->b_rotation = 0;
147         }
148         else if( !strcmp( psz_method, "vflip" ) )
149         {
150             p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
151             p_vout->p_sys->b_rotation = 0;
152         }
153         else if( !strcmp( psz_method, "90" ) )
154         {
155             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
156             p_vout->p_sys->b_rotation = 1;
157         }
158         else if( !strcmp( psz_method, "180" ) )
159         {
160             p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
161             p_vout->p_sys->b_rotation = 0;
162         }
163         else if( !strcmp( psz_method, "270" ) )
164         {
165             p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
166             p_vout->p_sys->b_rotation = 1;
167         }
168         else
169         {
170             msg_Err( p_vout, "no valid transform mode provided, using '90'" );
171             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
172             p_vout->p_sys->b_rotation = 1;
173         }
174
175         free( psz_method );
176     }
177     
178     return( 0 );
179 }
180
181 /*****************************************************************************
182  * vout_Init: initialize Transform video thread output method
183  *****************************************************************************/
184 static int vout_Init( vout_thread_t *p_vout )
185 {
186     int i_index;
187     picture_t *p_pic;
188     
189     I_OUTPUTPICTURES = 0;
190
191     /* Initialize the output structure */
192     p_vout->output.i_chroma = p_vout->render.i_chroma;
193     p_vout->output.i_width  = p_vout->render.i_width;
194     p_vout->output.i_height = p_vout->render.i_height;
195     p_vout->output.i_aspect = p_vout->render.i_aspect;
196
197     /* Try to open the real video output */
198     msg_Dbg( p_vout, "spawning the real video output" );
199
200     if( p_vout->p_sys->b_rotation )
201     {
202         p_vout->p_sys->p_vout =
203             vout_CreateThread( p_vout,
204                            p_vout->render.i_height, p_vout->render.i_width,
205                            p_vout->render.i_chroma,
206                            (u64)VOUT_ASPECT_FACTOR * (u64)VOUT_ASPECT_FACTOR
207                                / (u64)p_vout->render.i_aspect );
208     }
209     else
210     {
211         p_vout->p_sys->p_vout =
212             vout_CreateThread( p_vout,
213                            p_vout->render.i_width, p_vout->render.i_height,
214                            p_vout->render.i_chroma, p_vout->render.i_aspect );
215     }
216
217     /* Everything failed */
218     if( p_vout->p_sys->p_vout == NULL )
219     {
220         msg_Err( p_vout, "cannot open vout, aborting" );
221         return( 0 );
222     }
223  
224     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
225
226     return( 0 );
227 }
228
229 /*****************************************************************************
230  * vout_End: terminate Transform video thread output method
231  *****************************************************************************/
232 static void vout_End( vout_thread_t *p_vout )
233 {
234     int i_index;
235
236     /* Free the fake output buffers we allocated */
237     for( i_index = I_OUTPUTPICTURES ; i_index ; )
238     {
239         i_index--;
240         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
241     }
242 }
243
244 /*****************************************************************************
245  * vout_Destroy: destroy Transform video thread output method
246  *****************************************************************************
247  * Terminate an output method created by TransformCreateOutputMethod
248  *****************************************************************************/
249 static void vout_Destroy( vout_thread_t *p_vout )
250 {
251     vout_DestroyThread( p_vout->p_sys->p_vout );
252
253     free( p_vout->p_sys );
254 }
255
256 /*****************************************************************************
257  * vout_Manage: handle Transform events
258  *****************************************************************************
259  * This function should be called regularly by video output thread. It manages
260  * console events. It returns a non null value on error.
261  *****************************************************************************/
262 static int vout_Manage( vout_thread_t *p_vout )
263 {
264     return( 0 );
265 }
266
267 /*****************************************************************************
268  * vout_Render: displays previously rendered output
269  *****************************************************************************
270  * This function send the currently rendered image to Transform image, waits
271  * until it is displayed and switch the two rendering buffers, preparing next
272  * frame.
273  *****************************************************************************/
274 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
275 {
276     picture_t *p_outpic;
277     int i_index;
278
279     /* This is a new frame. Get a structure from the video_output. */
280     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
281               == NULL )
282     {
283         if( p_vout->b_die || p_vout->b_error )
284         {
285             return;
286         }
287         msleep( VOUT_OUTMEM_SLEEP );
288     }   
289
290     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
291     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
292
293     switch( p_vout->p_sys->i_mode )
294     {
295         case TRANSFORM_MODE_90:
296             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
297             {
298                 int i_pitch = p_pic->p[i_index].i_pitch;
299
300                 u8 *p_in = p_pic->p[i_index].p_pixels;
301
302                 u8 *p_out = p_outpic->p[i_index].p_pixels;
303                 u8 *p_out_end = p_out + p_outpic->p[i_index].i_lines
304                                          * p_outpic->p[i_index].i_pitch;
305
306                 for( ; p_out < p_out_end ; )
307                 {
308                     u8 *p_line_end;
309
310                     p_line_end = p_in + p_pic->p[i_index].i_lines
311                                          * p_pic->p[i_index].i_pitch;
312
313                     for( ; p_in < p_line_end ; )
314                     {
315                         p_line_end -= i_pitch;
316                         *(--p_out_end) = *p_line_end;
317                     }
318
319                     p_in++;
320                 }
321             }
322             break;
323
324         case TRANSFORM_MODE_180:
325             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
326             {
327                 u8 *p_in = p_pic->p[i_index].p_pixels;
328                 u8 *p_in_end = p_in + p_pic->p[i_index].i_lines
329                                        * p_pic->p[i_index].i_pitch;
330
331                 u8 *p_out = p_outpic->p[i_index].p_pixels;
332
333                 for( ; p_in < p_in_end ; )
334                 {
335                     *p_out++ = *(--p_in_end);
336                 }
337             }
338             break;
339
340         case TRANSFORM_MODE_270:
341             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
342             {
343                 int i_pitch = p_pic->p[i_index].i_pitch;
344
345                 u8 *p_in = p_pic->p[i_index].p_pixels;
346
347                 u8 *p_out = p_outpic->p[i_index].p_pixels;
348                 u8 *p_out_end = p_out + p_outpic->p[i_index].i_lines
349                                          * p_outpic->p[i_index].i_pitch;
350
351                 for( ; p_out < p_out_end ; )
352                 {
353                     u8 *p_in_end;
354
355                     p_in_end = p_in + p_pic->p[i_index].i_lines
356                                        * p_pic->p[i_index].i_pitch;
357
358                     for( ; p_in < p_in_end ; )
359                     {
360                         p_in_end -= i_pitch;
361                         *p_out++ = *p_in_end;
362                     }
363
364                     p_in++;
365                 }
366             }
367             break;
368
369         case TRANSFORM_MODE_VFLIP:
370             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
371             {
372                 u8 *p_in = p_pic->p[i_index].p_pixels;
373                 u8 *p_in_end = p_in + p_pic->p[i_index].i_lines
374                                        * p_pic->p[i_index].i_pitch;
375
376                 u8 *p_out = p_outpic->p[i_index].p_pixels;
377
378                 for( ; p_in < p_in_end ; )
379                 {
380                     p_in_end -= p_pic->p[i_index].i_pitch;
381                     p_vout->p_vlc->pf_memcpy( p_out, p_in_end,
382                                               p_pic->p[i_index].i_pitch );
383                     p_out += p_pic->p[i_index].i_pitch;
384                 }
385             }
386             break;
387
388         case TRANSFORM_MODE_HFLIP:
389             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
390             {
391                 u8 *p_in = p_pic->p[i_index].p_pixels;
392                 u8 *p_in_end = p_in + p_pic->p[i_index].i_lines
393                                        * p_pic->p[i_index].i_pitch;
394
395                 u8 *p_out = p_outpic->p[i_index].p_pixels;
396
397                 for( ; p_in < p_in_end ; )
398                 {
399                     u8 *p_line_end = p_in + p_pic->p[i_index].i_pitch;
400
401                     for( ; p_in < p_line_end ; )
402                     {
403                         *p_out++ = *(--p_line_end);
404                     }
405
406                     p_in += p_pic->p[i_index].i_pitch;
407                 }
408             }
409             break;
410
411         default:
412             break;
413     }
414
415     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
416
417     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
418 }
419
420 /*****************************************************************************
421  * vout_Display: displays previously rendered output
422  *****************************************************************************
423  * This function send the currently rendered image to Invert image, waits
424  * until it is displayed and switch the two rendering buffers, preparing next
425  * frame.
426  *****************************************************************************/
427 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
428 {
429     ;
430 }