]> git.sesse.net Git - vlc/blob - modules/video_output/picture.c
f36ab2157ba798e596ef866af39d67d291f11baa
[vlc] / modules / video_output / picture.c
1 /*****************************************************************************
2  * picture.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2005 VideoLAN
5  * $Id: picture.c 10081 2005-03-01 15:33:51Z dionoea $
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <stdlib.h>                                                /* free() */
30 #include <string.h>                                            /* strerror() */
31
32 #include <vlc/vlc.h>
33 #include <vlc/vout.h>
34
35 #include "vlc_image.h"
36
37 #include "picture.h"
38
39 /*****************************************************************************
40  * Local structures
41  *****************************************************************************/
42 struct vout_sys_t
43 {
44     picture_vout_t *p_picture_vout;
45     vlc_mutex_t *p_lock;
46
47     int i_picture_pos; /* picture position in p_picture_vout */
48     image_handler_t *p_image; /* filters for resizing */
49 #ifdef IMAGE_2PASSES
50     image_handler_t *p_image2;
51 #endif
52     int i_height, i_width;
53     mtime_t i_last_pic;
54 };
55
56 /* Delay after which the picture is blanked out if there hasn't been any
57  * new picture. */
58 #define BLANK_DELAY     I64C(1000000)
59
60 typedef void (* pf_release_t)( picture_t * );
61 static void ReleasePicture( picture_t *p_pic )
62 {
63     p_pic->i_refcount--;
64
65     if ( p_pic->i_refcount <= 0 )
66     {
67         if ( p_pic->p_sys != NULL )
68         {
69             pf_release_t pf_release = (pf_release_t)p_pic->p_sys;
70             p_pic->p_sys = NULL;
71             pf_release( p_pic );
72         }
73         else
74         {
75             if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
76             if( p_pic ) free( p_pic );
77         }
78     }
79 }
80
81 /*****************************************************************************
82  * Local prototypes
83  *****************************************************************************/
84 static int  Open    ( vlc_object_t * );
85 static void Close   ( vlc_object_t * );
86 static int  Init    ( vout_thread_t * );
87 static void End     ( vout_thread_t * );
88 static int  Manage  ( vout_thread_t * );
89 static void Display ( vout_thread_t *, picture_t * );
90
91 /*****************************************************************************
92  * Module descriptor
93  *****************************************************************************/
94 #define ID_TEXT N_("ID")
95 #define ID_LONGTEXT N_( \
96     "Specify an identifier string for this subpicture" )
97
98 #define WIDTH_TEXT N_("Video width")
99 #define WIDTH_LONGTEXT N_( \
100     "Allows you to specify the output video width." )
101 #define HEIGHT_TEXT N_("Video height")
102 #define HEIGHT_LONGTEXT N_( \
103     "Allows you to specify the output video height." )
104
105 vlc_module_begin();
106     set_shortname( _( "Picture" ) );
107     set_description(_("VLC internal picture video output") );
108     set_category( CAT_VIDEO );
109     set_subcategory( SUBCAT_VIDEO_VOUT );
110     set_capability( "video output", 0 );
111
112     add_string( "picture-id", "Id", NULL, ID_TEXT, ID_LONGTEXT, VLC_FALSE );
113     add_integer( "picture-width", 0, NULL, WIDTH_TEXT,
114                  WIDTH_LONGTEXT, VLC_TRUE );
115     add_integer( "picture-height", 0, NULL, HEIGHT_TEXT,
116                  HEIGHT_LONGTEXT, VLC_TRUE );
117
118     set_callbacks( Open, Close );
119
120     var_Create( p_module->p_libvlc, "picture-lock", VLC_VAR_MUTEX );
121 vlc_module_end();
122
123 /*****************************************************************************
124  * Open : allocate video thread output method
125  *****************************************************************************/
126 static int Open( vlc_object_t *p_this )
127 {
128     vout_thread_t *p_vout = (vout_thread_t *)p_this;
129     vout_sys_t *p_sys;
130     libvlc_t *p_libvlc = p_vout->p_libvlc;
131     picture_vout_t *p_picture_vout = NULL;
132     picture_vout_e_t *p_pic;
133     vlc_value_t val, lockval;
134
135     p_sys = p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
136     if( p_sys == NULL )
137     {
138         msg_Err( p_vout, "out of memory" );
139         return VLC_ENOMEM;
140     }
141
142     var_Get( p_libvlc, "picture-lock", &lockval );
143     p_sys->p_lock = lockval.p_address;
144     vlc_mutex_lock( p_sys->p_lock );
145
146     p_sys->i_picture_pos = -1;
147     if( var_Get( p_libvlc, "p_picture_vout", &val ) != VLC_SUCCESS )
148     {
149         p_picture_vout = malloc( sizeof( struct picture_vout_t ) );
150         if( p_picture_vout == NULL )
151         {
152             msg_Err( p_vout, "out of memory" );
153             return VLC_ENOMEM;
154         }
155
156         var_Create( p_libvlc, "p_picture_vout", VLC_VAR_ADDRESS );
157         val.p_address = p_picture_vout;
158         var_Set( p_libvlc, "p_picture_vout", val );
159
160         p_picture_vout->i_picture_num = 0;
161         p_picture_vout->p_pic = NULL;
162     }
163     else
164     {
165         int i;
166         p_picture_vout = val.p_address;
167         for ( i = 0; i < p_picture_vout->i_picture_num; i++ )
168         {
169             if ( p_picture_vout->p_pic[i].i_status == PICTURE_VOUT_E_AVAILABLE )
170                 break;
171         }
172
173         if ( i != p_picture_vout->i_picture_num )
174             p_sys->i_picture_pos = i;
175     }
176
177     p_sys->p_picture_vout = p_picture_vout;
178
179     if ( p_sys->i_picture_pos == -1 )
180     {
181         p_picture_vout->p_pic = realloc( p_picture_vout->p_pic,
182                                          (p_picture_vout->i_picture_num + 1)
183                                            * sizeof(picture_vout_e_t) );
184         p_sys->i_picture_pos = p_picture_vout->i_picture_num;
185         p_picture_vout->i_picture_num++;
186     }
187
188     p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
189     p_pic->p_picture = NULL;
190     p_pic->i_status = PICTURE_VOUT_E_OCCUPIED;
191
192     var_Create( p_vout, "picture-id", VLC_VAR_STRING );
193     var_Change( p_vout, "picture-id", VLC_VAR_INHERITVALUE, &val, NULL );
194     p_pic->psz_id = val.psz_string;
195
196     vlc_mutex_unlock( p_sys->p_lock );
197
198     var_Create( p_vout, "picture-height", VLC_VAR_INTEGER );
199     var_Change( p_vout, "picture-height", VLC_VAR_INHERITVALUE, &val, NULL );
200     p_sys->i_height = val.i_int; 
201
202     var_Create( p_vout, "picture-width", VLC_VAR_INTEGER );
203     var_Change( p_vout, "picture-width", VLC_VAR_INHERITVALUE, &val, NULL );
204     p_sys->i_width = val.i_int; 
205
206     if ( p_sys->i_height || p_sys->i_width )
207     {
208         p_sys->p_image = image_HandlerCreate( p_vout );
209 #ifdef IMAGE_2PASSES
210         p_sys->p_image2 = image_HandlerCreate( p_vout );
211 #endif
212     }
213
214     p_sys->i_last_pic = 0;
215
216     p_vout->pf_init = Init;
217     p_vout->pf_end = End;
218     p_vout->pf_manage = Manage;
219     p_vout->pf_render = NULL;
220     p_vout->pf_display = Display;
221
222     return VLC_SUCCESS;
223 }
224
225
226 /*****************************************************************************
227  * Init
228  *****************************************************************************/
229 static int Init( vout_thread_t *p_vout )
230 {
231     picture_t *p_pic;
232     int i_index;
233
234     I_OUTPUTPICTURES = 0;
235
236     p_vout->output.i_chroma = p_vout->render.i_chroma;
237     p_vout->output.i_width  = p_vout->render.i_width;
238     p_vout->output.i_height = p_vout->render.i_height;
239     p_vout->output.i_aspect = p_vout->render.i_aspect;
240
241     while( VLC_TRUE )
242     {
243         p_pic = NULL;
244
245         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
246         {
247             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
248             {
249                 p_pic = p_vout->p_picture + i_index;
250                 break;
251             }
252         }
253
254         if( p_pic == NULL )
255         {
256             return VLC_SUCCESS;
257         }
258
259         vout_AllocatePicture( VLC_OBJECT(p_vout), p_pic,
260                               p_vout->output.i_chroma,
261                               p_vout->output.i_width, p_vout->output.i_height,
262                               p_vout->output.i_aspect );
263
264         if( p_pic->i_planes == 0 )
265         {
266             return VLC_EGENERIC;
267         }
268
269         p_pic->i_status = DESTROYED_PICTURE;
270         p_pic->i_type   = DIRECT_PICTURE;
271
272         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
273
274         I_OUTPUTPICTURES++;
275
276         //return VLC_SUCCESS;
277     }
278
279 }
280
281 /*****************************************************************************
282  * End
283  *****************************************************************************/
284 static void End( vout_thread_t *p_vout )
285 {
286     return;
287 }
288
289 /*****************************************************************************
290  * Close
291  *****************************************************************************/
292 static void Close( vlc_object_t *p_this )
293 {
294     vout_thread_t *p_vout = (vout_thread_t *)p_this;
295     vout_sys_t *p_sys = p_vout->p_sys;
296     picture_vout_t *p_picture_vout = p_sys->p_picture_vout;
297     picture_vout_e_t *p_pic;
298     vlc_bool_t b_last_picture = VLC_TRUE;
299     int i;
300
301     vlc_mutex_lock( p_sys->p_lock );
302     p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
303
304     if( p_pic->p_picture )
305     {
306         p_pic->p_picture->pf_release( p_pic->p_picture );
307         p_pic->p_picture = NULL;
308     }
309     p_pic->i_status = PICTURE_VOUT_E_AVAILABLE;
310     if( p_pic->psz_id )
311         free( p_pic->psz_id );
312
313     for( i = 0; i < p_picture_vout->i_picture_num; i ++)
314     {
315         if( p_picture_vout->p_pic[i].i_status == PICTURE_VOUT_E_OCCUPIED )
316         {
317             b_last_picture = VLC_FALSE;
318             break;
319         }
320     }
321
322     if( b_last_picture )
323     {
324         free( p_picture_vout->p_pic );
325         free( p_picture_vout );
326         var_Destroy( p_this->p_libvlc, "p_picture_vout" );
327     }
328
329     vlc_mutex_unlock( p_sys->p_lock );
330
331     if ( p_sys->i_height || p_sys->i_width )
332     {
333         image_HandlerDelete( p_sys->p_image );
334 #ifdef IMAGE_2PASSES
335         image_HandlerDelete( p_sys->p_image2 );
336 #endif
337     }
338
339     free( p_sys );
340 }
341
342 /*****************************************************************************
343  * PushPicture : push a picture in the p_picture_vout structure
344  *****************************************************************************/
345 static void PushPicture( vout_thread_t *p_vout, picture_t *p_picture )
346 {
347     vout_sys_t *p_sys = p_vout->p_sys;
348     picture_vout_t *p_picture_vout = p_sys->p_picture_vout;
349     picture_vout_e_t *p_pic;
350
351     vlc_mutex_lock( p_sys->p_lock );
352     p_pic = &p_picture_vout->p_pic[p_sys->i_picture_pos];
353
354     if( p_pic->p_picture != NULL )
355     {
356         p_pic->p_picture->pf_release( p_pic->p_picture );
357     }
358     p_pic->p_picture = p_picture;
359
360     vlc_mutex_unlock( p_sys->p_lock );
361 }
362
363 /*****************************************************************************
364  * Manage
365  *****************************************************************************/
366 static int Manage( vout_thread_t *p_vout )
367 {
368     vout_sys_t *p_sys = p_vout->p_sys;
369
370     if ( mdate() - p_sys->i_last_pic > BLANK_DELAY )
371     {
372         /* Display black */
373 #if 0
374         picture_t *p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
375         int i;
376
377         if ( p_sys->i_height || p_sys->i_width )
378         {
379             vout_AllocatePicture( p_vout, p_new_pic,
380                                   VLC_FOURCC('Y','U','V','A'),
381                                   p_sys->i_width, p_sys->i_height,
382                                   p_vout->render.i_aspect );
383         }
384         else
385         {
386             vout_AllocatePicture( p_vout, p_new_pic, p_vout->render.i_chroma,
387                                   p_vout->render.i_width,
388                                   p_vout->render.i_height,
389                                   p_vout->render.i_aspect );
390         }
391
392         p_new_pic->i_refcount++;
393         p_new_pic->i_status = DESTROYED_PICTURE;
394         p_new_pic->i_type   = DIRECT_PICTURE;
395         p_new_pic->pf_release = ReleasePicture;
396
397         for ( i = 0; i < p_pic->i_planes; i++ )
398         {
399             /* This assumes planar YUV format */
400             p_vout->p_vlc->pf_memset( p_pic->p[i].p_pixels, i ? 0x80 : 0,
401                                       p_pic->p[i].i_lines
402                                        * p_pic->p[i].i_pitch );
403         }
404
405         PushPicture( p_vout, p_new_pic );
406 #else
407         PushPicture( p_vout, NULL );
408 #endif
409         p_sys->i_last_pic = INT64_MAX;
410     }
411
412     return VLC_SUCCESS;
413 }
414
415 /*****************************************************************************
416  * Display
417  *****************************************************************************/
418 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
419 {
420     vout_sys_t *p_sys = p_vout->p_sys;
421     picture_t *p_new_pic;
422
423     if ( p_sys->i_height || p_sys->i_width )
424     {
425         video_format_t fmt_out = {0}, fmt_in = {0};
426 #ifdef IMAGE_2PASSES
427         vide_format_t fmt_middle = {0};
428         picture_t *p_new_pic2;
429 #endif
430
431         fmt_in.i_chroma = p_vout->render.i_chroma;
432         fmt_in.i_width = p_vout->render.i_width;
433         fmt_in.i_height = p_vout->render.i_height;
434
435 #ifdef IMAGE_2PASSES
436         fmt_middle.i_chroma = p_vout->render.i_chroma;
437         fmt_middle.i_width = p_vout->p_sys->i_width;
438         fmt_middle.i_height = p_vout->p_sys->i_height;
439         fmt_middle.i_visible_width = fmt_middle.i_width;
440         fmt_middle.i_visible_height = fmt_middle.i_height;
441
442         p_new_pic2 = image_Convert( p_vout->p_sys->p_image2,
443                                     p_pic, &fmt_in, &fmt_middle );
444         if ( p_new_pic2 == NULL )
445         {
446             msg_Err( p_vout, "image resizing failed %dx%d->%dx%d %4.4s",
447                      p_vout->render.i_width, p_vout->render.i_height,
448                      fmt_middle.i_width, fmt_middle.i_height,
449                      (char *)&p_vout->render.i_chroma);
450             return;
451         }
452 #endif
453
454         fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
455         fmt_out.i_width = p_sys->i_width;
456         fmt_out.i_height = p_sys->i_height;
457         fmt_out.i_visible_width = fmt_out.i_width;
458         fmt_out.i_visible_height = fmt_out.i_height;
459
460 #ifdef IMAGE_2PASSES
461         p_new_pic = image_Convert( p_vout->p_sys->p_image,
462                                    p_new_pic2, &fmt_middle, &fmt_out );
463         p_new_pic2->pf_release( p_new_pic2 );
464 #else
465         p_new_pic = image_Convert( p_vout->p_sys->p_image,
466                                    p_pic, &fmt_in, &fmt_out );
467 #endif
468         if ( p_new_pic == NULL )
469         {
470             msg_Err( p_vout, "image conversion failed" );
471             return;
472         }
473     }
474     else
475     {
476         p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
477         vout_AllocatePicture( p_vout, p_new_pic, p_pic->format.i_chroma,
478                               p_pic->format.i_width, p_pic->format.i_height,
479                               p_vout->render.i_aspect );
480
481         vout_CopyPicture( p_vout, p_new_pic, p_pic );
482     }
483
484     p_new_pic->i_refcount = 1;
485     p_new_pic->i_status = DESTROYED_PICTURE;
486     p_new_pic->i_type   = DIRECT_PICTURE;
487     p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
488     p_new_pic->pf_release = ReleasePicture;
489
490     PushPicture( p_vout, p_new_pic );
491     p_sys->i_last_pic = p_pic->date;
492 }