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