]> git.sesse.net Git - vlc/blobdiff - src/misc/image.c
fix --no-stats in a few cases (there are more remaining)
[vlc] / src / misc / image.c
index 287285ebae6ada1cfbc666687e349ef897132d8b..040b93f5cb620e12fa9c430de3ff8dc436dd3dfc 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * image.c : wrapper for image reading/writing facilities
  *****************************************************************************
- * Copyright (C) 2004 VideoLAN
+ * Copyright (C) 2004 the VideoLAN team
  * $Id$
  *
  * Author: Gildas Bazin <gbazin@videolan.org>
@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /**
@@ -44,17 +44,22 @@ static block_t *ImageWrite( image_handler_t *, picture_t *,
 static int ImageWriteUrl( image_handler_t *, picture_t *,
                           video_format_t *, video_format_t *, const char * );
 
+static picture_t *ImageConvert( image_handler_t *, picture_t *,
+                                video_format_t *, video_format_t * );
+static picture_t *ImageFilter( image_handler_t *, picture_t *,
+                               video_format_t *, const char *psz_module );
+
 static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
 static void DeleteDecoder( decoder_t * );
 static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
                                  video_format_t * );
 static void DeleteEncoder( encoder_t * );
 static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
-                               video_format_t * );
+                               video_format_t *, const char * );
 static void DeleteFilter( filter_t * );
 
 static vlc_fourcc_t Ext2Fourcc( const char * );
-static const char *Fourcc2Ext( vlc_fourcc_t );
+/*static const char *Fourcc2Ext( vlc_fourcc_t );*/
 
 /**
  * Create an image_handler_t instance
@@ -71,6 +76,8 @@ image_handler_t *__image_HandlerCreate( vlc_object_t *p_this )
     p_image->pf_read_url = ImageReadUrl;
     p_image->pf_write = ImageWrite;
     p_image->pf_write_url = ImageWriteUrl;
+    p_image->pf_convert = ImageConvert;
+    p_image->pf_filter = ImageFilter;
 
     return p_image;
 }
@@ -99,7 +106,7 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
                              video_format_t *p_fmt_in,
                              video_format_t *p_fmt_out )
 {
-    picture_t *p_pic;
+    picture_t *p_pic = NULL, *p_tmp;
 
     /* Check if we can reuse the current decoder */
     if( p_image->p_dec &&
@@ -117,17 +124,29 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
     }
 
     p_block->i_pts = p_block->i_dts = mdate();
-    p_pic = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
-    p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
+    while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
+             != NULL )
+    {
+        if ( p_pic != NULL )
+            p_pic->pf_release( p_pic );
+        p_pic = p_tmp;
+    }
 
-    if( !p_pic )
+    if( p_pic == NULL )
     {
-        msg_Dbg( p_image->p_parent, "no image decoded" );
+        msg_Warn( p_image->p_parent, "no image decoded" );
         return 0;
     }
 
     if( !p_fmt_out->i_chroma )
         p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
+    if( !p_fmt_out->i_width && p_fmt_out->i_height )
+        p_fmt_out->i_width = p_fmt_out->i_height
+                              * p_image->p_dec->fmt_out.video.i_aspect
+                              / VOUT_ASPECT_FACTOR;
+    if( !p_fmt_out->i_height && p_fmt_out->i_width )
+        p_fmt_out->i_height = p_fmt_out->i_width * VOUT_ASPECT_FACTOR
+                               / p_image->p_dec->fmt_out.video.i_aspect;
     if( !p_fmt_out->i_width )
         p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
     if( !p_fmt_out->i_height )
@@ -153,7 +172,7 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
         {
             p_image->p_filter =
                 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
-                              p_fmt_out );
+                              p_fmt_out, NULL );
 
             if( !p_image->p_filter )
             {
@@ -251,7 +270,7 @@ static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
         p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
         p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height )
     {
-        picture_t *p_pif;
+        picture_t *p_tmp_pic;
 
         if( p_image->p_filter )
         if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
@@ -272,7 +291,7 @@ static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
 
             p_image->p_filter =
                 CreateFilter( p_image->p_parent, &fmt_in,
-                              &p_image->p_enc->fmt_in.video );
+                              &p_image->p_enc->fmt_in.video, NULL );
 
             if( !p_image->p_filter )
             {
@@ -290,12 +309,18 @@ static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
 
         pf_release = p_pic->pf_release;
         p_pic->pf_release = PicRelease; /* Small hack */
-        p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+        p_tmp_pic =
+            p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
         p_pic->pf_release = pf_release;
-        p_pic = p_pif;
-    }
 
-    p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
+        p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_tmp_pic );
+
+        p_image->p_filter->pf_vout_buffer_del( p_image->p_filter, p_tmp_pic );
+    }
+    else
+    {
+        p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
+    }
 
     if( !p_block )
     {
@@ -340,6 +365,130 @@ static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
     return p_block ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
+/**
+ * Convert an image to a different format
+ *
+ */
+
+static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
+                                video_format_t *p_fmt_in,
+                                video_format_t *p_fmt_out )
+{
+    void (*pf_release)( picture_t * );
+    picture_t *p_pif;
+
+    if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
+        p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
+        p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
+        p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
+    {
+        p_fmt_out->i_width =
+            p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
+            p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
+        p_fmt_out->i_visible_width =
+            p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
+            p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
+            p_fmt_out->i_sar_num;
+    }
+
+    if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
+    if( !p_fmt_out->i_width )
+        p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
+    if( !p_fmt_out->i_height )
+        p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
+    if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
+    if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
+    if( !p_fmt_out->i_aspect ) p_fmt_out->i_aspect = p_fmt_in->i_aspect;
+
+    if( p_image->p_filter )
+    if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
+        p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
+    {
+        /* We need to restart a new filter */
+        DeleteFilter( p_image->p_filter );
+        p_image->p_filter = 0;
+    }
+
+    /* Start a filter */
+    if( !p_image->p_filter )
+    {
+        es_format_t fmt_in;
+        es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
+        fmt_in.video = *p_fmt_in;
+
+        p_image->p_filter =
+            CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out, NULL );
+
+        if( !p_image->p_filter )
+        {
+            return NULL;
+        }
+    }
+    else
+    {
+        /* Filters should handle on-the-fly size changes */
+        p_image->p_filter->fmt_in.video = *p_fmt_in;
+        p_image->p_filter->fmt_out.video = *p_fmt_out;
+    }
+
+    pf_release = p_pic->pf_release;
+    p_pic->pf_release = PicRelease; /* Small hack */
+    p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+    p_pic->pf_release = pf_release;
+
+    if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
+        p_fmt_in->i_width == p_fmt_out->i_width &&
+        p_fmt_in->i_height == p_fmt_out->i_height )
+    {
+        /* Duplicate image */
+        p_pif = p_image->p_filter->pf_vout_buffer_new( p_image->p_filter );
+        if( p_pif ) vout_CopyPicture( p_image->p_parent, p_pif, p_pic );
+    }
+
+    return p_pif;
+}
+
+/**
+ * Filter an image with a psz_module filter
+ *
+ */
+
+static picture_t *ImageFilter( image_handler_t *p_image, picture_t *p_pic,
+                               video_format_t *p_fmt, const char *psz_module )
+{
+    void (*pf_release)( picture_t * );
+    picture_t *p_pif;
+
+    /* Start a filter */
+    if( !p_image->p_filter )
+    {
+        es_format_t fmt;
+        es_format_Init( &fmt, VIDEO_ES, p_fmt->i_chroma );
+        fmt.video = *p_fmt;
+
+        p_image->p_filter =
+            CreateFilter( p_image->p_parent, &fmt, &fmt.video, psz_module );
+
+        if( !p_image->p_filter )
+        {
+            return NULL;
+        }
+    }
+    else
+    {
+        /* Filters should handle on-the-fly size changes */
+        p_image->p_filter->fmt_in.video = *p_fmt;
+        p_image->p_filter->fmt_out.video = *p_fmt;
+    }
+
+    pf_release = p_pic->pf_release;
+    p_pic->pf_release = PicRelease; /* Small hack */
+    p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+    p_pic->pf_release = pf_release;
+
+    return p_pif;
+}
+
 /**
  * Misc functions
  *
@@ -359,6 +508,16 @@ static struct
     { VLC_FOURCC('p','g','m','y'), "pgmyuv" },
     { VLC_FOURCC('p','b','m',' '), "pbm" },
     { VLC_FOURCC('p','a','m',' '), "pam" },
+    { VLC_FOURCC('t','g','a',' '), "tga" },
+    { VLC_FOURCC('b','m','p',' '), "bmp" },
+    { VLC_FOURCC('p','n','m',' '), "pnm" },
+    { VLC_FOURCC('x','p','m',' '), "xpm" },
+    { VLC_FOURCC('x','c','f',' '), "xcf" },
+    { VLC_FOURCC('p','c','x',' '), "pcx" },
+    { VLC_FOURCC('g','i','f',' '), "gif" },
+    { VLC_FOURCC('t','i','f','f'), "tif" },
+    { VLC_FOURCC('t','i','f','f'), "tiff" },
+    { VLC_FOURCC('l','b','m',' '), "lbm" },
     { 0, NULL }
 };
 
@@ -384,6 +543,7 @@ static vlc_fourcc_t Ext2Fourcc( const char *psz_name )
     return 0;
 }
 
+/*
 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
 {
     int i;
@@ -395,6 +555,7 @@ static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
 
     return NULL;
 }
+*/
 
 static void video_release_buffer( picture_t *p_pic )
 {
@@ -512,7 +673,31 @@ static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
     {
         p_enc->fmt_in.video.i_width = fmt_out->i_width;
         p_enc->fmt_in.video.i_height = fmt_out->i_height;
+
+        if( fmt_out->i_visible_width > 0 &&
+            fmt_out->i_visible_height > 0 )
+        {
+            p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
+            p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
+        }
+        else
+        {
+            p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
+            p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
+        }
+    }
+    else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
+             fmt_out->i_sar_num * fmt_in->i_sar_den !=
+             fmt_out->i_sar_den * fmt_in->i_sar_num )
+    {
+        p_enc->fmt_in.video.i_width =
+            fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
+            fmt_in->i_sar_den / fmt_out->i_sar_num;
+        p_enc->fmt_in.video.i_visible_width =
+            fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
+            fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
     }
+
     p_enc->fmt_in.video.i_frame_rate = 25;
     p_enc->fmt_in.video.i_frame_rate_base = 1;
 
@@ -552,7 +737,8 @@ static void DeleteEncoder( encoder_t * p_enc )
 }
 
 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
-                               video_format_t *p_fmt_out )
+                               video_format_t *p_fmt_out,
+                               const char *psz_module )
 {
     filter_t *p_filter;
 
@@ -568,7 +754,8 @@ static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
     p_filter->fmt_out = *p_fmt_in;
     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
     p_filter->fmt_out.video = *p_fmt_out;
-    p_filter->p_module = module_Need( p_filter, "video filter2", 0, 0 );
+    p_filter->p_module = module_Need( p_filter, "video filter2", psz_module,
+                                      0 );
 
     if( !p_filter->p_module )
     {