Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

mosaic_bridge.c

00001 /*****************************************************************************
00002  * mosaic_bridge.c:
00003  *****************************************************************************
00004  * Copyright (C) 2004-2005 the VideoLAN team
00005  * $Id: mosaic_bridge.c 12075 2005-08-08 17:41:08Z dionoea $
00006  *
00007  * Authors: Antoine Cellerier <[email protected]>
00008  *          Christophe Massiot <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <errno.h>                                                 /* ENOMEM */
00029 #include <stdlib.h>                                                /* free() */
00030 #include <string.h>                                            /* strerror() */
00031 
00032 #include <vlc/vlc.h>
00033 #include <vlc/sout.h>
00034 #include <vlc/decoder.h>
00035 
00036 #include "vlc_image.h"
00037 
00038 #include "../video_filter/mosaic.h"
00039 
00040 /*****************************************************************************
00041  * Local structures
00042  *****************************************************************************/
00043 struct sout_stream_sys_t
00044 {
00045     bridged_es_t *p_es;
00046     vlc_mutex_t *p_lock;
00047 
00048     decoder_t       *p_decoder;
00049     image_handler_t *p_image; /* filter for resizing */
00050     int i_height, i_width;
00051     int i_sar_num, i_sar_den;
00052     char *psz_id;
00053     vlc_bool_t b_inited;
00054 };
00055 
00056 #define PICTURE_RING_SIZE 4
00057 struct decoder_owner_sys_t
00058 {
00059     picture_t *pp_pics[PICTURE_RING_SIZE];
00060 };
00061 
00062 typedef void (* pf_release_t)( picture_t * );
00063 static void ReleasePicture( picture_t *p_pic )
00064 {
00065     p_pic->i_refcount--;
00066 
00067     if ( p_pic->i_refcount <= 0 )
00068     {
00069         if ( p_pic->p_sys != NULL )
00070         {
00071             pf_release_t pf_release = (pf_release_t)p_pic->p_sys;
00072             p_pic->p_sys = NULL;
00073             pf_release( p_pic );
00074         }
00075         else
00076         {
00077             if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
00078             if( p_pic ) free( p_pic );
00079         }
00080     }
00081 }
00082 
00083 /*****************************************************************************
00084  * Local prototypes
00085  *****************************************************************************/
00086 static int  Open    ( vlc_object_t * );
00087 static void Close   ( vlc_object_t * );
00088 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00089 static int               Del ( sout_stream_t *, sout_stream_id_t * );
00090 static int               Send( sout_stream_t *, sout_stream_id_t *, block_t * );
00091 
00092 static void video_del_buffer( decoder_t *, picture_t * );
00093 static picture_t *video_new_buffer( decoder_t * );
00094 static void video_link_picture_decoder( decoder_t *, picture_t * );
00095 static void video_unlink_picture_decoder( decoder_t *, picture_t * );
00096 
00097 /*****************************************************************************
00098  * Module descriptor
00099  *****************************************************************************/
00100 #define ID_TEXT N_("ID")
00101 #define ID_LONGTEXT N_( \
00102     "Specify an identifier string for this subpicture" )
00103 
00104 #define WIDTH_TEXT N_("Video width")
00105 #define WIDTH_LONGTEXT N_( \
00106     "Allows you to specify the output video width." )
00107 #define HEIGHT_TEXT N_("Video height")
00108 #define HEIGHT_LONGTEXT N_( \
00109     "Allows you to specify the output video height." )
00110 #define RATIO_TEXT N_("Sample aspect ratio")
00111 #define RATIO_LONGTEXT N_( \
00112     "Sample aspect ratio of the destination (1:1, 3:4, 2:3)." )
00113 
00114 #define SOUT_CFG_PREFIX "sout-mosaic-bridge-"
00115 
00116 vlc_module_begin();
00117     set_shortname( _( "Mosaic bridge" ) );
00118     set_description(_("Mosaic bridge stream output") );
00119     set_capability( "sout stream", 0 );
00120     add_shortcut( "mosaic-bridge" );
00121 
00122     add_string( SOUT_CFG_PREFIX "id", "Id", NULL, ID_TEXT, ID_LONGTEXT,
00123                 VLC_FALSE );
00124     add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
00125                  WIDTH_LONGTEXT, VLC_TRUE );
00126     add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
00127                  HEIGHT_LONGTEXT, VLC_TRUE );
00128     add_string( SOUT_CFG_PREFIX "sar", "1:1", NULL, RATIO_TEXT,
00129                 RATIO_LONGTEXT, VLC_FALSE );
00130 
00131     set_callbacks( Open, Close );
00132 
00133     var_Create( p_module->p_libvlc, "mosaic-lock", VLC_VAR_MUTEX );
00134 vlc_module_end();
00135 
00136 static const char *ppsz_sout_options[] = {
00137     "id", "width", "height", "sar", NULL
00138 };
00139 
00140 /*****************************************************************************
00141  * Open
00142  *****************************************************************************/
00143 static int Open( vlc_object_t *p_this )
00144 {
00145     sout_stream_t     *p_stream = (sout_stream_t *)p_this;
00146     sout_stream_sys_t *p_sys;
00147     libvlc_t *p_libvlc = p_this->p_libvlc;
00148     vlc_value_t val;
00149 
00150     sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
00151                    p_stream->p_cfg );
00152 
00153     p_sys          = malloc( sizeof( sout_stream_sys_t ) );
00154     p_stream->p_sys = p_sys;
00155     p_sys->b_inited = VLC_FALSE;
00156 
00157     var_Get( p_libvlc, "mosaic-lock", &val );
00158     p_sys->p_lock = val.p_address;
00159 
00160     var_Get( p_stream, SOUT_CFG_PREFIX "id", &val );
00161     p_sys->psz_id = val.psz_string;
00162 
00163     var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
00164     p_sys->i_height = val.i_int;
00165 
00166     var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
00167     p_sys->i_width = val.i_int;
00168 
00169     var_Get( p_stream, SOUT_CFG_PREFIX "sar", &val );
00170     if ( val.psz_string )
00171     {
00172         char *psz_parser = strchr( val.psz_string, ':' );
00173 
00174         if( psz_parser )
00175         {
00176             *psz_parser++ = '\0';
00177             p_sys->i_sar_num = atoi( val.psz_string );
00178             p_sys->i_sar_den = atoi( psz_parser );
00179             vlc_ureduce( &p_sys->i_sar_num, &p_sys->i_sar_den,
00180                          p_sys->i_sar_num, p_sys->i_sar_den, 0 );
00181         }
00182         else
00183         {
00184             msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
00185             p_sys->i_sar_num = p_sys->i_sar_den = 1;
00186         }
00187 
00188         free( val.psz_string );
00189     }
00190     else
00191     {
00192         p_sys->i_sar_num = p_sys->i_sar_den = 1;
00193     }
00194 
00195     p_stream->pf_add    = Add;
00196     p_stream->pf_del    = Del;
00197     p_stream->pf_send   = Send;
00198 
00199     p_stream->p_sout->i_out_pace_nocontrol++;
00200 
00201     return VLC_SUCCESS;
00202 }
00203 
00204 /*****************************************************************************
00205  * Close
00206  *****************************************************************************/
00207 static void Close( vlc_object_t * p_this )
00208 {
00209     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
00210     sout_stream_sys_t *p_sys = p_stream->p_sys;
00211 
00212     p_stream->p_sout->i_out_pace_nocontrol--;
00213 
00214     if ( p_sys->psz_id )
00215         free( p_sys->psz_id );
00216 
00217     free( p_sys );
00218 }
00219 
00220 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00221 {
00222     sout_stream_sys_t *p_sys = p_stream->p_sys;
00223     bridge_t *p_bridge;
00224     bridged_es_t *p_es;
00225     int i;
00226 
00227     if ( p_sys->b_inited )
00228     {
00229         return NULL;
00230     }
00231 
00232     /* Create decoder object */
00233     p_sys->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
00234     vlc_object_attach( p_sys->p_decoder, p_stream );
00235     p_sys->p_decoder->p_module = NULL;
00236     p_sys->p_decoder->fmt_in = *p_fmt;
00237     p_sys->p_decoder->b_pace_control = VLC_FALSE;
00238     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
00239     p_sys->p_decoder->fmt_out.i_extra = 0;
00240     p_sys->p_decoder->fmt_out.p_extra = 0;
00241     p_sys->p_decoder->pf_decode_video = 0;
00242     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer;
00243     p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer;
00244     p_sys->p_decoder->pf_picture_link    = video_link_picture_decoder;
00245     p_sys->p_decoder->pf_picture_unlink  = video_unlink_picture_decoder;
00246     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
00247     for( i = 0; i < PICTURE_RING_SIZE; i++ )
00248         p_sys->p_decoder->p_owner->pp_pics[i] = 0;
00249     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
00250 
00251     p_sys->p_decoder->p_module =
00252         module_Need( p_sys->p_decoder, "decoder", "$codec", 0 );
00253 
00254     if( !p_sys->p_decoder->p_module )
00255     {
00256         msg_Err( p_stream, "cannot find decoder" );
00257         vlc_object_detach( p_sys->p_decoder );
00258         vlc_object_destroy( p_sys->p_decoder );
00259         return NULL;
00260     }
00261 
00262     p_sys->b_inited = VLC_TRUE;
00263     vlc_mutex_lock( p_sys->p_lock );
00264 
00265     p_bridge = GetBridge( p_stream );
00266     if ( p_bridge == NULL )
00267     {
00268         libvlc_t *p_libvlc = p_stream->p_libvlc;
00269         vlc_value_t val;
00270 
00271         p_bridge = malloc( sizeof( bridge_t ) );
00272 
00273         var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS );
00274         val.p_address = p_bridge;
00275         var_Set( p_libvlc, "mosaic-struct", val );
00276 
00277         p_bridge->i_es_num = 0;
00278         p_bridge->pp_es = NULL;
00279     }
00280 
00281     for ( i = 0; i < p_bridge->i_es_num; i++ )
00282     {
00283         if ( p_bridge->pp_es[i]->b_empty )
00284             break;
00285     }
00286 
00287     if ( i == p_bridge->i_es_num )
00288     {
00289         p_bridge->pp_es = realloc( p_bridge->pp_es,
00290                                    (p_bridge->i_es_num + 1)
00291                                      * sizeof(bridged_es_t *) );
00292         p_bridge->i_es_num++;
00293         p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
00294     }
00295 
00296     p_sys->p_es = p_es = p_bridge->pp_es[i];
00297 
00298     //p_es->fmt = *p_fmt;
00299     p_es->psz_id = p_sys->psz_id;
00300     p_es->p_picture = NULL;
00301     p_es->pp_last = &p_es->p_picture;
00302     p_es->b_empty = VLC_FALSE;
00303 
00304     vlc_mutex_unlock( p_sys->p_lock );
00305 
00306     if ( p_sys->i_height || p_sys->i_width )
00307     {
00308         p_sys->p_image = image_HandlerCreate( p_stream );
00309     }
00310 
00311     msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i );
00312 
00313     return (sout_stream_id_t *)p_sys;
00314 }
00315 
00316 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
00317 {
00318     sout_stream_sys_t *p_sys = p_stream->p_sys;
00319     bridge_t *p_bridge;
00320     bridged_es_t *p_es;
00321     vlc_bool_t b_last_es = VLC_TRUE;
00322     int i;
00323 
00324     if ( !p_sys->b_inited )
00325     {
00326         return VLC_SUCCESS;
00327     }
00328 
00329     if ( p_sys->p_decoder )
00330     {
00331         if( p_sys->p_decoder->p_module )
00332             module_Unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
00333         vlc_object_detach( p_sys->p_decoder );
00334         vlc_object_destroy( p_sys->p_decoder );
00335     }
00336 
00337     vlc_mutex_lock( p_sys->p_lock );
00338 
00339     p_bridge = GetBridge( p_stream );
00340     p_es = p_sys->p_es;
00341 
00342     p_es->b_empty = VLC_TRUE;
00343     while ( p_es->p_picture )
00344     {
00345         picture_t *p_next = p_es->p_picture->p_next;
00346         p_es->p_picture->pf_release( p_es->p_picture );
00347         p_es->p_picture = p_next;
00348     }
00349 
00350     for ( i = 0; i < p_bridge->i_es_num; i++ )
00351     {
00352         if ( !p_bridge->pp_es[i]->b_empty )
00353         {
00354             b_last_es = VLC_FALSE;
00355             break;
00356         }
00357     }
00358 
00359     if ( b_last_es )
00360     {
00361         libvlc_t *p_libvlc = p_stream->p_libvlc;
00362         for ( i = 0; i < p_bridge->i_es_num; i++ )
00363             free( p_bridge->pp_es[i] );
00364         free( p_bridge->pp_es );
00365         free( p_bridge );
00366         var_Destroy( p_libvlc, "mosaic-struct" );
00367     }
00368 
00369     vlc_mutex_unlock( p_sys->p_lock );
00370 
00371     if ( p_sys->i_height || p_sys->i_width )
00372     {
00373         image_HandlerDelete( p_sys->p_image );
00374     }
00375 
00376     p_sys->b_inited = VLC_FALSE;
00377 
00378     return VLC_SUCCESS;
00379 }
00380 
00381 /*****************************************************************************
00382  * PushPicture : push a picture in the mosaic-struct structure
00383  *****************************************************************************/
00384 static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
00385 {
00386     sout_stream_sys_t *p_sys = p_stream->p_sys;
00387     bridged_es_t *p_es = p_sys->p_es;
00388 
00389     vlc_mutex_lock( p_sys->p_lock );
00390 
00391     *p_es->pp_last = p_picture;
00392     p_picture->p_next = NULL;
00393     p_es->pp_last = &p_picture->p_next;
00394 
00395     vlc_mutex_unlock( p_sys->p_lock );
00396 }
00397 
00398 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00399                  block_t *p_buffer )
00400 {
00401     sout_stream_sys_t *p_sys = p_stream->p_sys;
00402     picture_t *p_pic;
00403 
00404     if ( (sout_stream_sys_t *)id != p_sys )
00405     {
00406         block_ChainRelease( p_buffer );
00407         return VLC_SUCCESS;
00408     }
00409 
00410     while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
00411                                                         &p_buffer )) )
00412     {
00413         picture_t *p_new_pic;
00414 
00415         if ( p_sys->i_height || p_sys->i_width )
00416         {
00417             video_format_t fmt_out = {0}, fmt_in = {0};
00418             fmt_in = p_sys->p_decoder->fmt_out.video;
00419 
00420             fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
00421 
00422             if ( !p_sys->i_height )
00423             {
00424                 fmt_out.i_width = p_sys->i_width;
00425                 fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
00426                     * p_sys->i_sar_num / p_sys->i_sar_den / fmt_in.i_aspect)
00427                       & ~0x1;
00428             }
00429             else if ( !p_sys->i_width )
00430             {
00431                 fmt_out.i_height = p_sys->i_height;
00432                 fmt_out.i_width = (p_sys->i_height * fmt_in.i_aspect
00433                     * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
00434                       & ~0x1;
00435             }
00436             else
00437             {
00438                 fmt_out.i_width = p_sys->i_width;
00439                 fmt_out.i_height = p_sys->i_height;
00440             }
00441             fmt_out.i_visible_width = fmt_out.i_width;
00442             fmt_out.i_visible_height = fmt_out.i_height;
00443 
00444             p_new_pic = image_Convert( p_sys->p_image,
00445                                        p_pic, &fmt_in, &fmt_out );
00446             if ( p_new_pic == NULL )
00447             {
00448                 msg_Err( p_stream, "image conversion failed" );
00449                 continue;
00450             }
00451         }
00452         else
00453         {
00454             p_new_pic = (picture_t*)malloc( sizeof(picture_t) );
00455             vout_AllocatePicture( p_stream, p_new_pic, p_pic->format.i_chroma,
00456                                   p_pic->format.i_width, p_pic->format.i_height,
00457                                   p_sys->p_decoder->fmt_out.video.i_aspect );
00458 
00459             vout_CopyPicture( p_stream, p_new_pic, p_pic );
00460         }
00461 
00462         p_new_pic->i_refcount = 1;
00463         p_new_pic->i_status = DESTROYED_PICTURE;
00464         p_new_pic->i_type   = DIRECT_PICTURE;
00465         p_new_pic->p_sys = (picture_sys_t *)p_new_pic->pf_release;
00466         p_new_pic->pf_release = ReleasePicture;
00467         p_new_pic->date = p_pic->date;
00468 
00469         p_pic->pf_release( p_pic );
00470         PushPicture( p_stream, p_new_pic );
00471     }
00472 
00473     return VLC_SUCCESS;
00474 }
00475 
00476 struct picture_sys_t
00477 {
00478     vlc_object_t *p_owner;
00479 };
00480 
00481 static void video_release_buffer( picture_t *p_pic )
00482 {
00483     if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
00484     {
00485         video_del_buffer( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
00486     }
00487     else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
00488 }
00489 
00490 static picture_t *video_new_buffer( decoder_t *p_dec )
00491 {
00492     picture_t **pp_ring = p_dec->p_owner->pp_pics;
00493     picture_t *p_pic;
00494     int i;
00495 
00496     /* Find an empty space in the picture ring buffer */
00497     for( i = 0; i < PICTURE_RING_SIZE; i++ )
00498     {
00499         if( pp_ring[i] != 0 && pp_ring[i]->i_status == DESTROYED_PICTURE )
00500         {
00501             pp_ring[i]->i_status = RESERVED_PICTURE;
00502             return pp_ring[i];
00503         }
00504     }
00505     for( i = 0; i < PICTURE_RING_SIZE; i++ )
00506     {
00507         if( pp_ring[i] == 0 ) break;
00508     }
00509 
00510     if( i == PICTURE_RING_SIZE )
00511     {
00512         msg_Err( p_dec, "decoder/filter is leaking pictures, "
00513                  "resetting its ring buffer" );
00514 
00515         for( i = 0; i < PICTURE_RING_SIZE; i++ )
00516         {
00517             pp_ring[i]->pf_release( pp_ring[i] );
00518         }
00519 
00520         i = 0;
00521     }
00522 
00523     p_pic = malloc( sizeof(picture_t) );
00524     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
00525     vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
00526                           p_dec->fmt_out.video.i_chroma,
00527                           p_dec->fmt_out.video.i_width,
00528                           p_dec->fmt_out.video.i_height,
00529                           p_dec->fmt_out.video.i_aspect );
00530 
00531     if( !p_pic->i_planes )
00532     {
00533         free( p_pic );
00534         return 0;
00535     }
00536 
00537     p_pic->pf_release = video_release_buffer;
00538     p_pic->p_sys = malloc( sizeof(picture_sys_t) );
00539     p_pic->p_sys->p_owner = VLC_OBJECT(p_dec);
00540     p_pic->i_status = RESERVED_PICTURE;
00541 
00542     pp_ring[i] = p_pic;
00543 
00544     return p_pic;
00545 }
00546 
00547 static void video_del_buffer( decoder_t *p_this, picture_t *p_pic )
00548 {
00549     p_pic->i_refcount = 0;
00550     p_pic->i_status = DESTROYED_PICTURE;
00551 }
00552 
00553 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
00554 {
00555     p_pic->i_refcount++;
00556 }
00557 
00558 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
00559 {
00560     video_release_buffer( p_pic );
00561 }
00562 

Generated on Tue Dec 20 10:14:49 2005 for vlc-0.8.4a by  doxygen 1.4.2