]> git.sesse.net Git - vlc/blob - src/misc/image.c
Removed es_format_t::i_aspect.
[vlc] / src / misc / image.c
1 /*****************************************************************************
2  * image.c : wrapper for image reading/writing facilities
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /**
25  * \file
26  * This file contains the functions to handle the image_handler_t type
27  */
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <ctype.h>
38 #include <errno.h>
39
40 #include <vlc_common.h>
41 #include <vlc_codec.h>
42 #include <vlc_meta.h>
43 #include <vlc_filter.h>
44 #include <vlc_es.h>
45 #include <vlc_image.h>
46 #include <vlc_stream.h>
47 #include <vlc_charset.h>
48 #include <vlc_sout.h>
49 #include <libvlc.h>
50
51 static picture_t *ImageRead( image_handler_t *, block_t *,
52                              video_format_t *, video_format_t * );
53 static picture_t *ImageReadUrl( image_handler_t *, const char *,
54                                 video_format_t *, video_format_t * );
55 static block_t *ImageWrite( image_handler_t *, picture_t *,
56                             video_format_t *, video_format_t * );
57 static int ImageWriteUrl( image_handler_t *, picture_t *,
58                           video_format_t *, video_format_t *, const char * );
59
60 static picture_t *ImageConvert( image_handler_t *, picture_t *,
61                                 video_format_t *, video_format_t * );
62 static picture_t *ImageFilter( image_handler_t *, picture_t *,
63                                video_format_t *, const char *psz_module );
64
65 static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
66 static void DeleteDecoder( decoder_t * );
67 static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
68                                  video_format_t * );
69 static void DeleteEncoder( encoder_t * );
70 static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
71                                video_format_t *, const char * );
72 static void DeleteFilter( filter_t * );
73
74 vlc_fourcc_t image_Type2Fourcc( const char * );
75 vlc_fourcc_t image_Ext2Fourcc( const char * );
76 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
77
78 /**
79  * Create an image_handler_t instance
80  *
81  */
82 image_handler_t *__image_HandlerCreate( vlc_object_t *p_this )
83 {
84     image_handler_t *p_image = calloc( 1, sizeof(image_handler_t) );
85     if( !p_image )
86         return NULL;
87
88     p_image->p_parent = p_this;
89
90     p_image->pf_read = ImageRead;
91     p_image->pf_read_url = ImageReadUrl;
92     p_image->pf_write = ImageWrite;
93     p_image->pf_write_url = ImageWriteUrl;
94     p_image->pf_convert = ImageConvert;
95     p_image->pf_filter = ImageFilter;
96
97     return p_image;
98 }
99
100 /**
101  * Delete the image_handler_t instance
102  *
103  */
104 void image_HandlerDelete( image_handler_t *p_image )
105 {
106     if( !p_image ) return;
107
108     if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
109     if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
110     if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
111
112     free( p_image );
113     p_image = NULL;
114 }
115
116 /**
117  * Read an image
118  *
119  */
120
121 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
122                              video_format_t *p_fmt_in,
123                              video_format_t *p_fmt_out )
124 {
125     picture_t *p_pic = NULL, *p_tmp;
126
127     /* Check if we can reuse the current decoder */
128     if( p_image->p_dec &&
129         p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
130     {
131         DeleteDecoder( p_image->p_dec );
132         p_image->p_dec = 0;
133     }
134
135     /* Start a decoder */
136     if( !p_image->p_dec )
137     {
138         p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
139         if( !p_image->p_dec ) return NULL;
140     }
141
142     p_block->i_pts = p_block->i_dts = mdate();
143     while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
144              != NULL )
145     {
146         if( p_pic != NULL )
147             picture_Release( p_pic );
148         p_pic = p_tmp;
149     }
150
151     if( p_pic == NULL )
152     {
153         msg_Warn( p_image->p_parent, "no image decoded" );
154         return 0;
155     }
156
157     if( !p_fmt_out->i_chroma )
158         p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
159     if( !p_fmt_out->i_width && p_fmt_out->i_height )
160         p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
161                              p_image->p_dec->fmt_out.video.i_sar_num *
162                              p_fmt_out->i_height /
163                              p_image->p_dec->fmt_out.video.i_height /
164                              p_image->p_dec->fmt_out.video.i_sar_den;
165
166     if( !p_fmt_out->i_height && p_fmt_out->i_width )
167         p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
168                               p_image->p_dec->fmt_out.video.i_sar_den *
169                               p_fmt_out->i_width /
170                               p_image->p_dec->fmt_out.video.i_width /
171                               p_image->p_dec->fmt_out.video.i_sar_num;
172     if( !p_fmt_out->i_width )
173         p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
174     if( !p_fmt_out->i_height )
175         p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
176
177     /* Check if we need chroma conversion or resizing */
178     if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
179         p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
180         p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
181     {
182         if( p_image->p_filter )
183         if( p_image->p_filter->fmt_in.video.i_chroma !=
184             p_image->p_dec->fmt_out.video.i_chroma ||
185             p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
186         {
187             /* We need to restart a new filter */
188             DeleteFilter( p_image->p_filter );
189             p_image->p_filter = 0;
190         }
191
192         /* Start a filter */
193         if( !p_image->p_filter )
194         {
195             p_image->p_filter =
196                 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
197                               p_fmt_out, NULL );
198
199             if( !p_image->p_filter )
200             {
201                 picture_Release( p_pic );
202                 return NULL;
203             }
204         }
205         else
206         {
207             /* Filters should handle on-the-fly size changes */
208             p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
209             p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
210             p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
211             p_image->p_filter->fmt_out.video = *p_fmt_out;
212         }
213
214         p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
215         *p_fmt_out = p_image->p_filter->fmt_out.video;
216     }
217     else *p_fmt_out = p_image->p_dec->fmt_out.video;
218
219     return p_pic;
220 }
221
222 static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
223                                 video_format_t *p_fmt_in,
224                                 video_format_t *p_fmt_out )
225 {
226     block_t *p_block;
227     picture_t *p_pic;
228     stream_t *p_stream = NULL;
229     int i_size;
230
231     p_stream = stream_UrlNew( p_image->p_parent, psz_url );
232
233     if( !p_stream )
234     {
235         msg_Dbg( p_image->p_parent, "could not open %s for reading",
236                  psz_url );
237         return NULL;
238     }
239
240     i_size = stream_Size( p_stream );
241
242     p_block = block_New( p_image->p_parent, i_size );
243
244     stream_Read( p_stream, p_block->p_buffer, i_size );
245
246     if( !p_fmt_in->i_chroma )
247     {
248         char *psz_mime = NULL;
249         stream_Control( p_stream, STREAM_GET_CONTENT_TYPE, &psz_mime );
250         if( psz_mime )
251             p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
252         free( psz_mime );
253     }
254     stream_Delete( p_stream );
255
256     if( !p_fmt_in->i_chroma )
257     {
258         /* Try to guess format from file name */
259         p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
260     }
261
262     p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
263
264     return p_pic;
265 }
266
267 /**
268  * Write an image
269  *
270  */
271
272 static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
273                             video_format_t *p_fmt_in,
274                             video_format_t *p_fmt_out )
275 {
276     block_t *p_block;
277
278     /* Check if we can reuse the current encoder */
279     if( p_image->p_enc &&
280         ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
281           p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
282           p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
283     {
284         DeleteEncoder( p_image->p_enc );
285         p_image->p_enc = 0;
286     }
287
288     /* Start an encoder */
289     if( !p_image->p_enc )
290     {
291         p_image->p_enc = CreateEncoder( p_image->p_parent,
292                                         p_fmt_in, p_fmt_out );
293         if( !p_image->p_enc ) return NULL;
294     }
295
296     /* Check if we need chroma conversion or resizing */
297     if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
298         p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
299         p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height )
300     {
301         picture_t *p_tmp_pic;
302
303         if( p_image->p_filter )
304         if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
305             p_image->p_filter->fmt_out.video.i_chroma !=
306             p_image->p_enc->fmt_in.video.i_chroma )
307         {
308             /* We need to restart a new filter */
309             DeleteFilter( p_image->p_filter );
310             p_image->p_filter = 0;
311         }
312
313         /* Start a filter */
314         if( !p_image->p_filter )
315         {
316             es_format_t fmt_in;
317             es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
318             fmt_in.video = *p_fmt_in;
319
320             p_image->p_filter =
321                 CreateFilter( p_image->p_parent, &fmt_in,
322                               &p_image->p_enc->fmt_in.video, NULL );
323
324             if( !p_image->p_filter )
325             {
326                 return NULL;
327             }
328         }
329         else
330         {
331             /* Filters should handle on-the-fly size changes */
332             p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
333             p_image->p_filter->fmt_out.video = *p_fmt_in;
334             p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
335             p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
336         }
337
338         picture_Hold( p_pic );
339
340         p_tmp_pic =
341             p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
342
343         p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_tmp_pic );
344
345         p_image->p_filter->pf_vout_buffer_del( p_image->p_filter, p_tmp_pic );
346     }
347     else
348     {
349         p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
350     }
351
352     if( !p_block )
353     {
354         msg_Dbg( p_image->p_parent, "no image encoded" );
355         return 0;
356     }
357
358     return p_block;
359 }
360
361 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
362                           video_format_t *p_fmt_in, video_format_t *p_fmt_out,
363                           const char *psz_url )
364 {
365     block_t *p_block;
366     FILE *file;
367
368     if( !p_fmt_out->i_chroma )
369     {
370         /* Try to guess format from file name */
371         p_fmt_out->i_chroma = image_Ext2Fourcc( psz_url );
372     }
373
374     file = utf8_fopen( psz_url, "wb" );
375     if( !file )
376     {
377         msg_Err( p_image->p_parent, "%s: %m", psz_url );
378         return VLC_EGENERIC;
379     }
380
381     p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
382
383     int err = 0;
384     if( p_block )
385     {
386         if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, file ) != 1 )
387             err = errno;
388         block_Release( p_block );
389     }
390
391     if( fclose( file ) && !err )
392         err = errno;
393
394     if( err )
395     {
396        errno = err;
397        msg_Err( p_image->p_parent, "%s: %m", psz_url );
398     }
399
400     return err ? VLC_EGENERIC : VLC_SUCCESS;
401 }
402
403 /**
404  * Convert an image to a different format
405  *
406  */
407
408 static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
409                                 video_format_t *p_fmt_in,
410                                 video_format_t *p_fmt_out )
411 {
412     picture_t *p_pif;
413
414     if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
415         p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
416         p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
417         p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
418     {
419         p_fmt_out->i_width =
420             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
421             p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
422         p_fmt_out->i_visible_width =
423             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
424             p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
425             p_fmt_out->i_sar_num;
426     }
427
428     if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
429     if( !p_fmt_out->i_width )
430         p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
431     if( !p_fmt_out->i_height )
432         p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
433     if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
434     if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
435
436     if( p_image->p_filter )
437     if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
438         p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
439     {
440         /* We need to restart a new filter */
441         DeleteFilter( p_image->p_filter );
442         p_image->p_filter = NULL;
443     }
444
445     /* Start a filter */
446     if( !p_image->p_filter )
447     {
448         es_format_t fmt_in;
449         es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
450         fmt_in.video = *p_fmt_in;
451
452         p_image->p_filter =
453             CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out, NULL );
454
455         if( !p_image->p_filter )
456         {
457             return NULL;
458         }
459     }
460     else
461     {
462         /* Filters should handle on-the-fly size changes */
463         p_image->p_filter->fmt_in.video = *p_fmt_in;
464         p_image->p_filter->fmt_out.video = *p_fmt_out;
465     }
466
467     picture_Hold( p_pic );
468
469     p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
470
471     if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
472         p_fmt_in->i_width == p_fmt_out->i_width &&
473         p_fmt_in->i_height == p_fmt_out->i_height )
474     {
475         /* Duplicate image */
476         picture_Release( p_pif ); /* XXX: Better fix must be possible */
477         p_pif = p_image->p_filter->pf_vout_buffer_new( p_image->p_filter );
478         if( p_pif )
479             picture_Copy( p_pif, p_pic );
480     }
481
482     return p_pif;
483 }
484
485 /**
486  * Filter an image with a psz_module filter
487  *
488  */
489
490 static picture_t *ImageFilter( image_handler_t *p_image, picture_t *p_pic,
491                                video_format_t *p_fmt, const char *psz_module )
492 {
493     /* Start a filter */
494     if( !p_image->p_filter )
495     {
496         es_format_t fmt;
497         es_format_Init( &fmt, VIDEO_ES, p_fmt->i_chroma );
498         fmt.video = *p_fmt;
499
500         p_image->p_filter =
501             CreateFilter( p_image->p_parent, &fmt, &fmt.video, psz_module );
502
503         if( !p_image->p_filter )
504         {
505             return NULL;
506         }
507     }
508     else
509     {
510         /* Filters should handle on-the-fly size changes */
511         p_image->p_filter->fmt_in.video = *p_fmt;
512         p_image->p_filter->fmt_out.video = *p_fmt;
513     }
514
515     picture_Hold( p_pic );
516
517     return p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
518 }
519
520 /**
521  * Misc functions
522  *
523  */
524 static const struct
525 {
526     vlc_fourcc_t i_codec;
527     const char *psz_ext;
528
529 } ext_table[] =
530 {
531     { VLC_CODEC_JPEG,              "jpeg" },
532     { VLC_CODEC_JPEG,              "jpg"  },
533     { VLC_CODEC_JPEGLS,            "ljpg" },
534     { VLC_CODEC_PNG,               "png" },
535     { VLC_CODEC_PGM,               "pgm" },
536     { VLC_CODEC_PGMYUV,            "pgmyuv" },
537     { VLC_FOURCC('p','b','m',' '), "pbm" },
538     { VLC_FOURCC('p','a','m',' '), "pam" },
539     { VLC_CODEC_TARGA,             "tga" },
540     { VLC_CODEC_BMP,               "bmp" },
541     { VLC_CODEC_PNM,               "pnm" },
542     { VLC_FOURCC('x','p','m',' '), "xpm" },
543     { VLC_FOURCC('x','c','f',' '), "xcf" },
544     { VLC_CODEC_PCX,               "pcx" },
545     { VLC_CODEC_GIF,               "gif" },
546     { VLC_CODEC_TIFF,              "tif" },
547     { VLC_CODEC_TIFF,              "tiff" },
548     { VLC_FOURCC('l','b','m',' '), "lbm" },
549     { VLC_CODEC_PPM,               "ppm" },
550     { 0, NULL }
551 };
552
553 vlc_fourcc_t image_Type2Fourcc( const char *psz_type )
554 {
555     int i;
556
557     for( i = 0; ext_table[i].i_codec; i++ )
558         if( !strcasecmp( ext_table[i].psz_ext, psz_type ) )
559             return ext_table[i].i_codec;
560
561     return 0;
562 }
563
564 vlc_fourcc_t image_Ext2Fourcc( const char *psz_name )
565 {
566     psz_name = strrchr( psz_name, '.' );
567     if( !psz_name ) return 0;
568     psz_name++;
569
570     return image_Type2Fourcc( psz_name );
571 }
572
573 /*
574 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
575 {
576     int i;
577
578     for( i = 0; ext_table[i].i_codec != 0; i++ )
579     {
580         if( ext_table[i].i_codec == i_codec ) return ext_table[i].psz_ext;
581     }
582
583     return NULL;
584 }
585 */
586
587 static const struct
588 {
589     vlc_fourcc_t i_codec;
590     const char *psz_mime;
591 } mime_table[] =
592 {
593     { VLC_CODEC_BMP,               "image/bmp" },
594     { VLC_CODEC_BMP,               "image/x-bmp" },
595     { VLC_CODEC_BMP,               "image/x-bitmap" },
596     { VLC_CODEC_BMP,               "image/x-ms-bmp" },
597     { VLC_CODEC_PNM,               "image/x-portable-anymap" },
598     { VLC_CODEC_PNM,               "image/x-portable-bitmap" },
599     { VLC_CODEC_PNM,               "image/x-portable-graymap" },
600     { VLC_CODEC_PNM,               "image/x-portable-pixmap" },
601     { VLC_CODEC_GIF,               "image/gif" },
602     { VLC_CODEC_JPEG,              "image/jpeg" },
603     { VLC_CODEC_PCX,               "image/pcx" },
604     { VLC_CODEC_PNG,               "image/png" },
605     { VLC_CODEC_TIFF,              "image/tiff" },
606     { VLC_CODEC_TARGA,             "iamge/x-tga" },
607     { VLC_FOURCC('x','p','m',' '), "image/x-xpixmap" },
608     { 0, NULL }
609 };
610
611 vlc_fourcc_t image_Mime2Fourcc( const char *psz_mime )
612 {
613     int i;
614     for( i = 0; mime_table[i].i_codec; i++ )
615         if( !strcmp( psz_mime, mime_table[i].psz_mime ) )
616             return mime_table[i].i_codec;
617     return 0;
618 }
619
620
621 static picture_t *video_new_buffer( decoder_t *p_dec )
622 {
623     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
624     return picture_NewFromFormat( &p_dec->fmt_out.video );
625 }
626
627 static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
628 {
629     if( p_pic->i_refcount != 1 )
630         msg_Err( p_dec, "invalid picture reference count" );
631
632     p_pic->i_refcount = 0;
633     picture_Delete( p_pic );
634 }
635
636 static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
637 {
638     (void)p_dec;
639     picture_Hold( p_pic );
640 }
641
642 static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
643 {
644     (void)p_dec;
645     picture_Release( p_pic );
646 }
647
648 static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
649 {
650     decoder_t *p_dec;
651
652     p_dec = vlc_object_create( p_this, VLC_OBJECT_DECODER );
653     if( p_dec == NULL )
654         return NULL;
655
656     p_dec->p_module = NULL;
657     es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
658     es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
659     p_dec->fmt_in.video = *fmt;
660     p_dec->b_pace_control = true;
661
662     p_dec->pf_vout_buffer_new = video_new_buffer;
663     p_dec->pf_vout_buffer_del = video_del_buffer;
664     p_dec->pf_picture_link    = video_link_picture;
665     p_dec->pf_picture_unlink  = video_unlink_picture;
666
667     vlc_object_attach( p_dec, p_this );
668
669     /* Find a suitable decoder module */
670     p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
671     if( !p_dec->p_module )
672     {
673         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
674                  "VLC probably does not support this image format.",
675                  (char*)&p_dec->fmt_in.i_codec );
676
677         DeleteDecoder( p_dec );
678         return NULL;
679     }
680
681     return p_dec;
682 }
683
684 static void DeleteDecoder( decoder_t * p_dec )
685 {
686     vlc_object_detach( p_dec );
687
688     if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
689
690     es_format_Clean( &p_dec->fmt_in );
691     es_format_Clean( &p_dec->fmt_out );
692
693     if( p_dec->p_description )
694         vlc_meta_Delete( p_dec->p_description );
695
696     vlc_object_release( p_dec );
697     p_dec = NULL;
698 }
699
700 static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
701                                  video_format_t *fmt_out )
702 {
703     encoder_t *p_enc;
704
705     p_enc = sout_EncoderCreate( p_this );
706     if( p_enc == NULL )
707         return NULL;
708
709     p_enc->p_module = NULL;
710     es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
711     p_enc->fmt_in.video = *fmt_in;
712     if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
713     {
714         p_enc->fmt_in.video.i_width = fmt_out->i_width;
715         p_enc->fmt_in.video.i_height = fmt_out->i_height;
716
717         if( fmt_out->i_visible_width > 0 &&
718             fmt_out->i_visible_height > 0 )
719         {
720             p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
721             p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
722         }
723         else
724         {
725             p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
726             p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
727         }
728     }
729     else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
730              fmt_out->i_sar_num * fmt_in->i_sar_den !=
731              fmt_out->i_sar_den * fmt_in->i_sar_num )
732     {
733         p_enc->fmt_in.video.i_width =
734             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
735             fmt_in->i_sar_den / fmt_out->i_sar_num;
736         p_enc->fmt_in.video.i_visible_width =
737             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
738             fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
739     }
740
741     p_enc->fmt_in.video.i_frame_rate = 25;
742     p_enc->fmt_in.video.i_frame_rate_base = 1;
743
744     es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
745     p_enc->fmt_out.video = *fmt_out;
746     p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
747     p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
748
749     vlc_object_attach( p_enc, p_this );
750
751     /* Find a suitable decoder module */
752     p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
753     if( !p_enc->p_module )
754     {
755         msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
756                  "VLC probably does not support this image format.",
757                  (char*)&p_enc->fmt_out.i_codec );
758
759         DeleteEncoder( p_enc );
760         return NULL;
761     }
762     p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
763
764     return p_enc;
765 }
766
767 static void DeleteEncoder( encoder_t * p_enc )
768 {
769     vlc_object_detach( p_enc );
770
771     if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
772
773     es_format_Clean( &p_enc->fmt_in );
774     es_format_Clean( &p_enc->fmt_out );
775
776     vlc_object_release( p_enc );
777     p_enc = NULL;
778 }
779
780 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
781                                video_format_t *p_fmt_out,
782                                const char *psz_module )
783 {
784     static const char typename[] = "filter";
785     filter_t *p_filter;
786
787     p_filter = vlc_custom_create( p_this, sizeof(filter_t),
788                                   VLC_OBJECT_GENERIC, typename );
789     vlc_object_attach( p_filter, p_this );
790
791     p_filter->pf_vout_buffer_new =
792         (picture_t *(*)(filter_t *))video_new_buffer;
793     p_filter->pf_vout_buffer_del =
794         (void (*)(filter_t *, picture_t *))video_del_buffer;
795
796     p_filter->fmt_in = *p_fmt_in;
797     p_filter->fmt_out = *p_fmt_in;
798     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
799     p_filter->fmt_out.video = *p_fmt_out;
800     p_filter->p_module = module_need( p_filter, "video filter2",
801                                       psz_module, false );
802
803     if( !p_filter->p_module )
804     {
805         msg_Dbg( p_filter, "no video filter found" );
806         DeleteFilter( p_filter );
807         return NULL;
808     }
809
810     return p_filter;
811 }
812
813 static void DeleteFilter( filter_t * p_filter )
814 {
815     vlc_object_detach( p_filter );
816
817     if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
818
819     es_format_Clean( &p_filter->fmt_in );
820     es_format_Clean( &p_filter->fmt_out );
821
822     vlc_object_release( p_filter );
823 }