~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to modules/video_filter/clone.c

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * clone.c : Clone video plugin for vlc
 
3
 *****************************************************************************
 
4
 * Copyright (C) 2002, 2003 VideoLAN
 
5
 * $Id: clone.c 7522 2004-04-27 16:35:15Z sam $
 
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 <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 VOUTSEPARATOR ','
 
36
 
 
37
/*****************************************************************************
 
38
 * Local prototypes
 
39
 *****************************************************************************/
 
40
static int  Create    ( vlc_object_t * );
 
41
static void Destroy   ( vlc_object_t * );
 
42
 
 
43
static int  Init      ( vout_thread_t * );
 
44
static void End       ( vout_thread_t * );
 
45
static void Render    ( vout_thread_t *, picture_t * );
 
46
 
 
47
static void RemoveAllVout  ( vout_thread_t *p_vout );
 
48
 
 
49
static int  SendEvents( vlc_object_t *, char const *,
 
50
                        vlc_value_t, vlc_value_t, void * );
 
51
 
 
52
/*****************************************************************************
 
53
 * Module descriptor
 
54
 *****************************************************************************/
 
55
#define COUNT_TEXT N_("Number of clones")
 
56
#define COUNT_LONGTEXT N_("Select the number of video windows in which to "\
 
57
    "clone the video")
 
58
 
 
59
#define VOUTLIST_TEXT N_("List of video output modules")
 
60
#define VOUTLIST_LONGTEXT N_("Select the specific video output modules that you want to activate")
 
61
 
 
62
vlc_module_begin();
 
63
    set_description( _("Clone video filter") );
 
64
    set_capability( "video filter", 0 );
 
65
    
 
66
    add_integer( "clone-count", 2, NULL, COUNT_TEXT, COUNT_LONGTEXT, VLC_FALSE );
 
67
    add_string ( "clone-vout-list", NULL, NULL, VOUTLIST_TEXT, VOUTLIST_LONGTEXT, VLC_FALSE );
 
68
    
 
69
    add_shortcut( "clone" );
 
70
    set_callbacks( Create, Destroy );
 
71
vlc_module_end();
 
72
 
 
73
/*****************************************************************************
 
74
 * vout_sys_t: Clone video output method descriptor
 
75
 *****************************************************************************
 
76
 * This structure is part of the video output thread descriptor.
 
77
 * It describes the Clone specific properties of an output thread.
 
78
 *****************************************************************************/
 
79
struct vout_sys_t
 
80
{
 
81
    int    i_clones;
 
82
 
 
83
    /* list of vout modules to use. "default" will launch a default
 
84
     * module. If specified, overrides the setting in i_clones (which it
 
85
     * sets to the list length) */
 
86
    char **ppsz_vout_list;
 
87
 
 
88
    vout_thread_t **pp_vout;
 
89
};
 
90
 
 
91
/*****************************************************************************
 
92
 * Control: control facility for the vout (forwards to child vout)
 
93
 *****************************************************************************/
 
94
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
 
95
{
 
96
    int i_vout;
 
97
    for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ )
 
98
    {
 
99
        vout_vaControl( p_vout->p_sys->pp_vout[ i_vout ], i_query, args );
 
100
    }
 
101
    return VLC_SUCCESS;
 
102
}
 
103
 
 
104
/*****************************************************************************
 
105
 * Create: allocates Clone video thread output method
 
106
 *****************************************************************************
 
107
 * This function allocates and initializes a Clone vout method.
 
108
 *****************************************************************************/
 
109
static int Create( vlc_object_t *p_this )
 
110
{
 
111
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
112
    char *psz_clonelist;
 
113
 
 
114
    /* Allocate structure */
 
115
    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
 
116
    if( p_vout->p_sys == NULL )
 
117
    {
 
118
        msg_Err( p_vout, "out of memory" );
 
119
        return VLC_ENOMEM;
 
120
    }
 
121
 
 
122
    p_vout->pf_init = Init;
 
123
    p_vout->pf_end = End;
 
124
    p_vout->pf_manage = NULL;
 
125
    p_vout->pf_render = Render;
 
126
    p_vout->pf_display = NULL;
 
127
    p_vout->pf_control = Control;
 
128
 
 
129
    psz_clonelist = config_GetPsz( p_vout, "clone-vout-list" );
 
130
    if( psz_clonelist )
 
131
    {
 
132
        int i_dummy;
 
133
        char *psz_token;
 
134
 
 
135
        /* Count the number of defined vout */
 
136
        p_vout->p_sys->i_clones = 1;
 
137
        i_dummy = 0;
 
138
        while( psz_clonelist[i_dummy] != 0 )
 
139
        {
 
140
            if( psz_clonelist[i_dummy] == VOUTSEPARATOR )
 
141
                p_vout->p_sys->i_clones++;
 
142
            i_dummy++;
 
143
        }
 
144
 
 
145
        p_vout->p_sys->ppsz_vout_list = malloc( p_vout->p_sys->i_clones
 
146
                                                * sizeof(char *) );
 
147
        if( !p_vout->p_sys->ppsz_vout_list )
 
148
        {
 
149
            msg_Err( p_vout, "out of memory" );
 
150
            free( p_vout->p_sys );
 
151
            return VLC_ENOMEM;
 
152
        }
 
153
 
 
154
        /* Tokenize the list */
 
155
        i_dummy = 0;
 
156
        psz_token = psz_clonelist;
 
157
        while( psz_token && *psz_token )
 
158
        {
 
159
           char *psz_module;
 
160
           psz_module = psz_token;
 
161
           psz_token = strchr( psz_module, VOUTSEPARATOR );
 
162
           if( psz_token )
 
163
           {
 
164
               *psz_token = '\0';
 
165
               psz_token++;
 
166
           }
 
167
           p_vout->p_sys->ppsz_vout_list[i_dummy] = strdup( psz_module );
 
168
           i_dummy++;
 
169
        }
 
170
 
 
171
        free( psz_clonelist );
 
172
    }
 
173
    else
 
174
    {
 
175
        /* No list was specified. We will use the default vout, and get
 
176
         * the number of clones from clone-count */
 
177
        p_vout->p_sys->i_clones = config_GetInt( p_vout, "clone-count" );
 
178
        p_vout->p_sys->ppsz_vout_list = NULL;
 
179
    }
 
180
 
 
181
    p_vout->p_sys->i_clones = __MAX( 1, __MIN( 99, p_vout->p_sys->i_clones ) );
 
182
 
 
183
    msg_Dbg( p_vout, "spawning %i clone(s)", p_vout->p_sys->i_clones );
 
184
 
 
185
    p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_clones *
 
186
                                     sizeof(vout_thread_t *) );
 
187
    if( p_vout->p_sys->pp_vout == NULL )
 
188
    {
 
189
        msg_Err( p_vout, "out of memory" );
 
190
        free( p_vout->p_sys );
 
191
        return VLC_ENOMEM;
 
192
    }
 
193
 
 
194
    return VLC_SUCCESS;
 
195
}
 
196
 
 
197
/*****************************************************************************
 
198
 * Init: initialize Clone video thread output method
 
199
 *****************************************************************************/
 
200
static int Init( vout_thread_t *p_vout )
 
201
{
 
202
    int   i_index, i_vout;
 
203
    picture_t *p_pic;
 
204
    char *psz_default_vout;
 
205
 
 
206
    I_OUTPUTPICTURES = 0;
 
207
 
 
208
    /* Initialize the output structure */
 
209
    p_vout->output.i_chroma = p_vout->render.i_chroma;
 
210
    p_vout->output.i_width  = p_vout->render.i_width;
 
211
    p_vout->output.i_height = p_vout->render.i_height;
 
212
    p_vout->output.i_aspect = p_vout->render.i_aspect;
 
213
 
 
214
    /* Try to open the real video output */
 
215
    msg_Dbg( p_vout, "spawning the real video outputs" );
 
216
 
 
217
    /* Save the default vout */
 
218
    psz_default_vout = config_GetPsz( p_vout, "vout" );
 
219
 
 
220
    for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ )
 
221
    {
 
222
        if( p_vout->p_sys->ppsz_vout_list == NULL 
 
223
            || ( !strncmp( p_vout->p_sys->ppsz_vout_list[i_vout],
 
224
                           "default", 8 ) ) )
 
225
        {
 
226
            p_vout->p_sys->pp_vout[i_vout] =
 
227
                vout_Create( p_vout, p_vout->render.i_width,
 
228
                             p_vout->render.i_height, p_vout->render.i_chroma, 
 
229
                             p_vout->render.i_aspect );
 
230
        }
 
231
        else
 
232
        {
 
233
            /* create the appropriate vout instead of the default one */
 
234
            config_PutPsz( p_vout, "vout",
 
235
                           p_vout->p_sys->ppsz_vout_list[i_vout] );
 
236
            p_vout->p_sys->pp_vout[i_vout] =
 
237
                vout_Create( p_vout, p_vout->render.i_width,
 
238
                             p_vout->render.i_height, p_vout->render.i_chroma, 
 
239
                             p_vout->render.i_aspect );
 
240
 
 
241
            /* Reset the default value */
 
242
            config_PutPsz( p_vout, "vout", psz_default_vout );
 
243
        }
 
244
 
 
245
        if( p_vout->p_sys->pp_vout[ i_vout ] == NULL )
 
246
        {
 
247
            msg_Err( p_vout, "failed to clone %i vout threads",
 
248
                     p_vout->p_sys->i_clones );
 
249
            p_vout->p_sys->i_clones = i_vout;
 
250
            if( psz_default_vout ) free( psz_default_vout );
 
251
            RemoveAllVout( p_vout );
 
252
            return VLC_EGENERIC;
 
253
        }
 
254
 
 
255
        ADD_CALLBACKS( p_vout->p_sys->pp_vout[ i_vout ], SendEvents );
 
256
    }
 
257
 
 
258
    if( psz_default_vout ) free( psz_default_vout );
 
259
    ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
 
260
 
 
261
    ADD_PARENT_CALLBACKS( SendEventsToChild );
 
262
 
 
263
    return VLC_SUCCESS;
 
264
}
 
265
 
 
266
/*****************************************************************************
 
267
 * End: terminate Clone video thread output method
 
268
 *****************************************************************************/
 
269
static void End( vout_thread_t *p_vout )
 
270
{
 
271
    int i_index;
 
272
 
 
273
    /* Free the fake output buffers we allocated */
 
274
    for( i_index = I_OUTPUTPICTURES ; i_index ; )
 
275
    {
 
276
        i_index--;
 
277
        free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
 
278
    }
 
279
}
 
280
 
 
281
/*****************************************************************************
 
282
 * Destroy: destroy Clone video thread output method
 
283
 *****************************************************************************
 
284
 * Terminate an output method created by CloneCreateOutputMethod
 
285
 *****************************************************************************/
 
286
static void Destroy( vlc_object_t *p_this )
 
287
{
 
288
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
289
 
 
290
    RemoveAllVout( p_vout );
 
291
 
 
292
    DEL_PARENT_CALLBACKS( SendEventsToChild );
 
293
 
 
294
    free( p_vout->p_sys->pp_vout );
 
295
    free( p_vout->p_sys );
 
296
}
 
297
 
 
298
/*****************************************************************************
 
299
 * Render: displays previously rendered output
 
300
 *****************************************************************************
 
301
 * This function send the currently rendered image to Clone image, waits
 
302
 * until it is displayed and switch the two rendering buffers, preparing next
 
303
 * frame.
 
304
 *****************************************************************************/
 
305
static void Render( vout_thread_t *p_vout, picture_t *p_pic )
 
306
{
 
307
    picture_t *p_outpic = NULL;
 
308
    int i_vout, i_plane;
 
309
 
 
310
    for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ )
 
311
    {
 
312
        while( ( p_outpic =
 
313
            vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ], 0, 0, 0 )
 
314
               ) == NULL )
 
315
        {
 
316
            if( p_vout->b_die || p_vout->b_error )
 
317
            {
 
318
                vout_DestroyPicture(
 
319
                    p_vout->p_sys->pp_vout[ i_vout ], p_outpic );
 
320
                return;
 
321
            }
 
322
 
 
323
            msleep( VOUT_OUTMEM_SLEEP );
 
324
        }
 
325
 
 
326
        vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ],
 
327
                          p_outpic, p_pic->date );
 
328
        vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic );
 
329
 
 
330
        for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
 
331
        {
 
332
            uint8_t *p_in, *p_in_end, *p_out;
 
333
            int i_in_pitch = p_pic->p[i_plane].i_pitch;
 
334
            const int i_out_pitch = p_outpic->p[i_plane].i_pitch;
 
335
            const int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
 
336
 
 
337
            p_in = p_pic->p[i_plane].p_pixels;
 
338
            p_out = p_outpic->p[i_plane].p_pixels;
 
339
 
 
340
            if( i_in_pitch == i_copy_pitch
 
341
                 && i_out_pitch == i_copy_pitch )
 
342
            {
 
343
                p_vout->p_vlc->pf_memcpy( p_out, p_in, i_in_pitch
 
344
                                           * p_outpic->p[i_plane].i_lines );
 
345
            }
 
346
            else
 
347
            {
 
348
                p_in_end = p_in + i_in_pitch * p_outpic->p[i_plane].i_lines;
 
349
 
 
350
                while( p_in < p_in_end )
 
351
                {
 
352
                    p_vout->p_vlc->pf_memcpy( p_out, p_in, i_copy_pitch );
 
353
                    p_in += i_in_pitch;
 
354
                    p_out += i_out_pitch;
 
355
                }
 
356
            }
 
357
        }
 
358
 
 
359
        vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic );
 
360
        vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic );
 
361
    }
 
362
}
 
363
 
 
364
/*****************************************************************************
 
365
 * RemoveAllVout: destroy all the child video output threads
 
366
 *****************************************************************************/
 
367
static void RemoveAllVout( vout_thread_t *p_vout )
 
368
{
 
369
    while( p_vout->p_sys->i_clones )
 
370
    {
 
371
         --p_vout->p_sys->i_clones;
 
372
         DEL_CALLBACKS( p_vout->p_sys->pp_vout[p_vout->p_sys->i_clones],
 
373
                        SendEvents );
 
374
         vlc_object_detach( p_vout->p_sys->pp_vout[p_vout->p_sys->i_clones] );
 
375
         vout_Destroy( p_vout->p_sys->pp_vout[p_vout->p_sys->i_clones] );
 
376
    }
 
377
}
 
378
 
 
379
/*****************************************************************************
 
380
 * SendEvents: forward mouse and keyboard events to the parent p_vout
 
381
 *****************************************************************************/
 
382
static int SendEvents( vlc_object_t *p_this, char const *psz_var,
 
383
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
 
384
{
 
385
    var_Set( (vlc_object_t *)p_data, psz_var, newval );
 
386
 
 
387
    return VLC_SUCCESS;
 
388
}
 
389
 
 
390
/*****************************************************************************
 
391
 * SendEventsToChild: forward events to the child/children vout
 
392
 *****************************************************************************/
 
393
static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
 
394
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
 
395
{
 
396
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
397
    int i_vout;
 
398
 
 
399
    for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ )
 
400
    {
 
401
        var_Set( p_vout->p_sys->pp_vout[ i_vout ], psz_var, newval );
 
402
 
 
403
        if( !strcmp( psz_var, "fullscreen" ) ) break;
 
404
    }
 
405
 
 
406
    return VLC_SUCCESS;
 
407
}