]> git.sesse.net Git - vlc/blob - src/misc/image.c
9a17d8079c6dae2e611ed9bb44438466b0c8a0f6
[vlc] / src / misc / image.c
1 /*****************************************************************************
2  * image.c : wrapper for image reading/writing facilities
3  *****************************************************************************
4  * Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 #include <ctype.h>
33 #include <vlc/vlc.h>
34 #include <vlc/decoder.h>
35 #include <vlc_filter.h>
36 #include <vlc_image.h>
37
38 static picture_t *ImageRead( image_handler_t *, block_t *,
39                              video_format_t *, video_format_t * );
40 static picture_t *ImageReadUrl( image_handler_t *, const char *,
41                                 video_format_t *, video_format_t * );
42 static block_t *ImageWrite( image_handler_t *, picture_t *,
43                             video_format_t *, video_format_t * );
44 static int ImageWriteUrl( image_handler_t *, picture_t *,
45                           video_format_t *, video_format_t *, const char * );
46
47 static picture_t *ImageConvert( image_handler_t *, picture_t *,
48                                 video_format_t *, video_format_t * );
49
50 static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
51 static void DeleteDecoder( decoder_t * );
52 static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
53                                  video_format_t * );
54 static void DeleteEncoder( encoder_t * );
55 static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
56                                video_format_t * );
57 static void DeleteFilter( filter_t * );
58
59 static vlc_fourcc_t Ext2Fourcc( const char * );
60 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
61
62 /**
63  * Create an image_handler_t instance
64  *
65  */
66 image_handler_t *__image_HandlerCreate( vlc_object_t *p_this )
67 {
68     image_handler_t *p_image = malloc( sizeof(image_handler_t) );
69
70     memset( p_image, 0, sizeof(image_handler_t) );
71     p_image->p_parent = p_this;
72
73     p_image->pf_read = ImageRead;
74     p_image->pf_read_url = ImageReadUrl;
75     p_image->pf_write = ImageWrite;
76     p_image->pf_write_url = ImageWriteUrl;
77     p_image->pf_convert = ImageConvert;
78
79     return p_image;
80 }
81
82 /**
83  * Delete the image_handler_t instance
84  *
85  */
86 void image_HandlerDelete( image_handler_t *p_image )
87 {
88     if( !p_image ) return;
89
90     if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
91     if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
92     if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
93
94     free( p_image );
95 }
96
97 /**
98  * Read an image
99  *
100  */
101
102 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
103                              video_format_t *p_fmt_in,
104                              video_format_t *p_fmt_out )
105 {
106     picture_t *p_pic = NULL, *p_tmp;
107
108     /* Check if we can reuse the current decoder */
109     if( p_image->p_dec &&
110         p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
111     {
112         DeleteDecoder( p_image->p_dec );
113         p_image->p_dec = 0;
114     }
115
116     /* Start a decoder */
117     if( !p_image->p_dec )
118     {
119         p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
120         if( !p_image->p_dec ) return NULL;
121     }
122
123     p_block->i_pts = p_block->i_dts = mdate();
124     p_pic = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
125     while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
126              != NULL )
127     {
128         if ( p_pic != NULL )
129             p_pic->pf_release( p_pic );
130         p_pic = p_tmp;
131     }
132
133     if( p_pic == NULL )
134     {
135         msg_Warn( p_image->p_parent, "no image decoded" );
136         return 0;
137     }
138
139     if( !p_fmt_out->i_chroma )
140         p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
141     if( !p_fmt_out->i_width )
142         p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
143     if( !p_fmt_out->i_height )
144         p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
145
146     /* Check if we need chroma conversion or resizing */
147     if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
148         p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
149         p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
150     {
151         if( p_image->p_filter )
152         if( p_image->p_filter->fmt_in.video.i_chroma !=
153             p_image->p_dec->fmt_out.video.i_chroma ||
154             p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
155         {
156             /* We need to restart a new filter */
157             DeleteFilter( p_image->p_filter );
158             p_image->p_filter = 0;
159         }
160
161         /* Start a filter */
162         if( !p_image->p_filter )
163         {
164             p_image->p_filter =
165                 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
166                               p_fmt_out );
167
168             if( !p_image->p_filter )
169             {
170                 p_pic->pf_release( p_pic );
171                 return NULL;
172             }
173         }
174         else
175         {
176             /* Filters should handle on-the-fly size changes */
177             p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
178             p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
179             p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
180             p_image->p_filter->fmt_out.video = *p_fmt_out;
181         }
182
183         p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
184         *p_fmt_out = p_image->p_filter->fmt_out.video;
185     }
186     else *p_fmt_out = p_image->p_dec->fmt_out.video;
187
188     return p_pic;
189 }
190
191 static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
192                                 video_format_t *p_fmt_in,
193                                 video_format_t *p_fmt_out )
194 {
195     block_t *p_block;
196     picture_t *p_pic;
197     FILE *file;
198     int i_size;
199
200     file = fopen( psz_url, "rb" );
201     if( !file )
202     {
203         msg_Dbg( p_image->p_parent, "could not open file %s for reading",
204                  psz_url );
205         return NULL;
206     }
207
208     fseek( file, 0, SEEK_END );
209     i_size = ftell( file );
210     fseek( file, 0, SEEK_SET );
211
212     p_block = block_New( p_image->p_parent, i_size );
213     fread( p_block->p_buffer, sizeof(char), i_size, file );
214     fclose( file );
215
216     if( !p_fmt_in->i_chroma )
217     {
218         /* Try to guess format from file name */
219         p_fmt_in->i_chroma = Ext2Fourcc( psz_url );
220     }
221
222     p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
223
224     return p_pic;
225 }
226
227 /**
228  * Write an image
229  *
230  */
231
232 void PicRelease( picture_t *p_pic ){};
233
234 static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
235                             video_format_t *p_fmt_in,
236                             video_format_t *p_fmt_out )
237 {
238     block_t *p_block;
239     void (*pf_release)( picture_t * );
240
241     /* Check if we can reuse the current encoder */
242     if( p_image->p_enc &&
243         ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
244           p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
245           p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
246     {
247         DeleteEncoder( p_image->p_enc );
248         p_image->p_enc = 0;
249     }
250
251     /* Start an encoder */
252     if( !p_image->p_enc )
253     {
254         p_image->p_enc = CreateEncoder( p_image->p_parent,
255                                         p_fmt_in, p_fmt_out );
256         if( !p_image->p_enc ) return NULL;
257     }
258
259     /* Check if we need chroma conversion or resizing */
260     if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
261         p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
262         p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height )
263     {
264         picture_t *p_pif;
265
266         if( p_image->p_filter )
267         if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
268             p_image->p_filter->fmt_out.video.i_chroma !=
269             p_image->p_enc->fmt_in.video.i_chroma )
270         {
271             /* We need to restart a new filter */
272             DeleteFilter( p_image->p_filter );
273             p_image->p_filter = 0;
274         }
275
276         /* Start a filter */
277         if( !p_image->p_filter )
278         {
279             es_format_t fmt_in;
280             es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
281             fmt_in.video = *p_fmt_in;
282
283             p_image->p_filter =
284                 CreateFilter( p_image->p_parent, &fmt_in,
285                               &p_image->p_enc->fmt_in.video );
286
287             if( !p_image->p_filter )
288             {
289                 return NULL;
290             }
291         }
292         else
293         {
294             /* Filters should handle on-the-fly size changes */
295             p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
296             p_image->p_filter->fmt_out.video = *p_fmt_in;
297             p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
298             p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
299         }
300
301         pf_release = p_pic->pf_release;
302         p_pic->pf_release = PicRelease; /* Small hack */
303         p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
304         p_pic->pf_release = pf_release;
305         p_pic = p_pif;
306     }
307
308     p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
309
310     if( !p_block )
311     {
312         msg_Dbg( p_image->p_parent, "no image encoded" );
313         return 0;
314     }
315
316     return p_block;
317 }
318
319 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
320                           video_format_t *p_fmt_in, video_format_t *p_fmt_out,
321                           const char *psz_url )
322 {
323     block_t *p_block;
324     FILE *file;
325
326     if( !p_fmt_out->i_chroma )
327     {
328         /* Try to guess format from file name */
329         p_fmt_out->i_chroma = Ext2Fourcc( psz_url );
330     }
331
332     file = fopen( psz_url, "wb" );
333     if( !file )
334     {
335         msg_Dbg( p_image->p_parent, "could not open file %s for writing",
336                  psz_url );
337         return VLC_EGENERIC;
338     }
339
340     p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
341
342     if( p_block )
343     {
344         fwrite( p_block->p_buffer, sizeof(char), p_block->i_buffer, file );
345         block_Release( p_block );
346     }
347
348     fclose( file );
349
350     return p_block ? VLC_SUCCESS : VLC_EGENERIC;
351 }
352
353 /**
354  * Convert an image to a different format
355  *
356  */
357
358 static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
359                                 video_format_t *p_fmt_in,
360                                 video_format_t *p_fmt_out )
361 {
362     void (*pf_release)( picture_t * );
363     picture_t *p_pif;
364
365     if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
366         p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
367         p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
368         p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
369     {
370         p_fmt_out->i_width =
371             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
372             p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
373         p_fmt_out->i_visible_width =
374             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
375             p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
376             p_fmt_out->i_sar_num;
377     }
378
379     if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
380     if( !p_fmt_out->i_width )
381         p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
382     if( !p_fmt_out->i_height )
383         p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
384     if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
385     if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
386     if( !p_fmt_out->i_aspect ) p_fmt_out->i_aspect = p_fmt_in->i_aspect;
387
388     if( p_image->p_filter )
389     if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
390         p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
391     {
392         /* We need to restart a new filter */
393         DeleteFilter( p_image->p_filter );
394         p_image->p_filter = 0;
395     }
396
397     /* Start a filter */
398     if( !p_image->p_filter )
399     {
400         es_format_t fmt_in;
401         es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
402         fmt_in.video = *p_fmt_in;
403
404         p_image->p_filter =
405             CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out );
406
407         if( !p_image->p_filter )
408         {
409             return NULL;
410         }
411     }
412     else
413     {
414         /* Filters should handle on-the-fly size changes */
415         p_image->p_filter->fmt_in.video = *p_fmt_in;
416         p_image->p_filter->fmt_out.video = *p_fmt_out;
417     }
418
419     pf_release = p_pic->pf_release;
420     p_pic->pf_release = PicRelease; /* Small hack */
421     p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
422     p_pic->pf_release = pf_release;
423
424     if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
425         p_fmt_in->i_width == p_fmt_out->i_width &&
426         p_fmt_in->i_height == p_fmt_out->i_height )
427     {
428         /* Duplicate image */
429         p_pif = p_image->p_filter->pf_vout_buffer_new( p_image->p_filter );
430         if( p_pif ) vout_CopyPicture( p_image->p_parent, p_pif, p_pic );
431     }
432
433     return p_pif;
434 }
435
436 /**
437  * Misc functions
438  *
439  */
440 static struct
441 {
442     vlc_fourcc_t i_codec;
443     char *psz_ext;
444
445 } ext_table[] =
446 {
447     { VLC_FOURCC('j','p','e','g'), "jpeg" },
448     { VLC_FOURCC('j','p','e','g'), "jpg"  },
449     { VLC_FOURCC('l','j','p','g'), "ljpg" },
450     { VLC_FOURCC('p','n','g',' '), "png" },
451     { VLC_FOURCC('p','g','m',' '), "pgm" },
452     { VLC_FOURCC('p','g','m','y'), "pgmyuv" },
453     { VLC_FOURCC('p','b','m',' '), "pbm" },
454     { VLC_FOURCC('p','a','m',' '), "pam" },
455     { VLC_FOURCC('t','g','a',' '), "tga" },
456     { VLC_FOURCC('b','m','p',' '), "bmp" },
457     { VLC_FOURCC('p','n','m',' '), "pnm" },
458     { VLC_FOURCC('x','p','m',' '), "xpm" },
459     { VLC_FOURCC('x','c','f',' '), "xcf" },
460     { VLC_FOURCC('p','c','x',' '), "pcx" },
461     { VLC_FOURCC('g','i','f',' '), "gif" },
462     { VLC_FOURCC('t','i','f','f'), "tif" },
463     { VLC_FOURCC('t','i','f','f'), "tiff" },
464     { VLC_FOURCC('l','b','m',' '), "lbm" },
465     { 0, NULL }
466 };
467
468 static vlc_fourcc_t Ext2Fourcc( const char *psz_name )
469 {
470     int i;
471
472     psz_name = strrchr( psz_name, '.' );
473     if( !psz_name ) return 0;
474     psz_name++;
475
476     for( i = 0; ext_table[i].i_codec; i++ )
477     {
478         int j;
479         for( j = 0; toupper(ext_table[i].psz_ext[j]) == toupper(psz_name[j]);
480              j++ )
481         {
482             if( !ext_table[i].psz_ext[j] && !psz_name[j] )
483                 return ext_table[i].i_codec;
484         }
485     }
486
487     return 0;
488 }
489
490 /*
491 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
492 {
493     int i;
494
495     for( i = 0; ext_table[i].i_codec != 0; i++ )
496     {
497         if( ext_table[i].i_codec == i_codec ) return ext_table[i].psz_ext;
498     }
499
500     return NULL;
501 }
502 */
503
504 static void video_release_buffer( picture_t *p_pic )
505 {
506     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
507     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
508     if( p_pic ) free( p_pic );
509 }
510
511 static picture_t *video_new_buffer( decoder_t *p_dec )
512 {
513     picture_t *p_pic = malloc( sizeof(picture_t) );
514
515     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
516     vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
517                           p_dec->fmt_out.video.i_chroma,
518                           p_dec->fmt_out.video.i_width,
519                           p_dec->fmt_out.video.i_height,
520                           p_dec->fmt_out.video.i_aspect );
521
522     if( !p_pic->i_planes )
523     {
524         free( p_pic );
525         return 0;
526     }
527
528     p_pic->pf_release = video_release_buffer;
529     p_pic->i_status = RESERVED_PICTURE;
530     p_pic->p_sys = NULL;
531
532     return p_pic;
533 }
534
535 static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
536 {
537     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
538     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
539     if( p_pic ) free( p_pic );
540 }
541
542 static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
543 {
544 }
545
546 static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
547 {
548 }
549
550 static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
551 {
552     decoder_t *p_dec;
553
554     p_dec = vlc_object_create( p_this, VLC_OBJECT_DECODER );
555     if( p_dec == NULL )
556     {
557         msg_Err( p_this, "out of memory" );
558         return NULL;
559     }
560
561     p_dec->p_module = NULL;
562     es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
563     es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
564     p_dec->fmt_in.video = *fmt;
565     p_dec->b_pace_control = VLC_TRUE;
566
567     p_dec->pf_vout_buffer_new = video_new_buffer;
568     p_dec->pf_vout_buffer_del = video_del_buffer;
569     p_dec->pf_picture_link    = video_link_picture;
570     p_dec->pf_picture_unlink  = video_unlink_picture;
571
572     vlc_object_attach( p_dec, p_this );
573
574     /* Find a suitable decoder module */
575     p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
576     if( !p_dec->p_module )
577     {
578         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
579                  "VLC probably does not support this image format.",
580                  (char*)&p_dec->fmt_in.i_codec );
581
582         DeleteDecoder( p_dec );
583         return NULL;
584     }
585
586     return p_dec;
587 }
588
589 static void DeleteDecoder( decoder_t * p_dec )
590 {
591     vlc_object_detach( p_dec );
592
593     if( p_dec->p_module ) module_Unneed( p_dec, p_dec->p_module );
594
595     es_format_Clean( &p_dec->fmt_in );
596     es_format_Clean( &p_dec->fmt_out );
597
598     vlc_object_destroy( p_dec );
599 }
600
601 static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
602                                  video_format_t *fmt_out )
603 {
604     encoder_t *p_enc;
605
606     p_enc = vlc_object_create( p_this, VLC_OBJECT_ENCODER );
607     if( p_enc == NULL )
608     {
609         msg_Err( p_this, "out of memory" );
610         return NULL;
611     }
612
613     p_enc->p_module = NULL;
614     es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
615     p_enc->fmt_in.video = *fmt_in;
616     if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
617     {
618         p_enc->fmt_in.video.i_width = fmt_out->i_width;
619         p_enc->fmt_in.video.i_height = fmt_out->i_height;
620
621         if( fmt_out->i_visible_width > 0 &&
622             fmt_out->i_visible_height > 0 )
623         {
624             p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
625             p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
626         }
627         else
628         {
629             p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
630             p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
631         }
632     }
633     else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
634              fmt_out->i_sar_num * fmt_in->i_sar_den !=
635              fmt_out->i_sar_den * fmt_in->i_sar_num )
636     {
637         p_enc->fmt_in.video.i_width =
638             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
639             fmt_in->i_sar_den / fmt_out->i_sar_num;
640         p_enc->fmt_in.video.i_visible_width =
641             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
642             fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
643     }
644
645     p_enc->fmt_in.video.i_frame_rate = 25;
646     p_enc->fmt_in.video.i_frame_rate_base = 1;
647
648     es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
649     p_enc->fmt_out.video = *fmt_out;
650     p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
651     p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
652
653     vlc_object_attach( p_enc, p_this );
654
655     /* Find a suitable decoder module */
656     p_enc->p_module = module_Need( p_enc, "encoder", 0, 0 );
657     if( !p_enc->p_module )
658     {
659         msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
660                  "VLC probably does not support this image format.",
661                  (char*)&p_enc->fmt_out.i_codec );
662
663         DeleteEncoder( p_enc );
664         return NULL;
665     }
666     p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
667
668     return p_enc;
669 }
670
671 static void DeleteEncoder( encoder_t * p_enc )
672 {
673     vlc_object_detach( p_enc );
674
675     if( p_enc->p_module ) module_Unneed( p_enc, p_enc->p_module );
676
677     es_format_Clean( &p_enc->fmt_in );
678     es_format_Clean( &p_enc->fmt_out );
679
680     vlc_object_destroy( p_enc );
681 }
682
683 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
684                                video_format_t *p_fmt_out )
685 {
686     filter_t *p_filter;
687
688     p_filter = vlc_object_create( p_this, VLC_OBJECT_FILTER );
689     vlc_object_attach( p_filter, p_this );
690
691     p_filter->pf_vout_buffer_new =
692         (picture_t *(*)(filter_t *))video_new_buffer;
693     p_filter->pf_vout_buffer_del =
694         (void (*)(filter_t *, picture_t *))video_del_buffer;
695
696     p_filter->fmt_in = *p_fmt_in;
697     p_filter->fmt_out = *p_fmt_in;
698     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
699     p_filter->fmt_out.video = *p_fmt_out;
700     p_filter->p_module = module_Need( p_filter, "video filter2", 0, 0 );
701
702     if( !p_filter->p_module )
703     {
704         msg_Dbg( p_filter, "no video filter found" );
705         DeleteFilter( p_filter );
706         return NULL;
707     }
708
709     return p_filter;
710 }
711
712 static void DeleteFilter( filter_t * p_filter )
713 {
714     vlc_object_detach( p_filter );
715
716     if( p_filter->p_module ) module_Unneed( p_filter, p_filter->p_module );
717
718     es_format_Clean( &p_filter->fmt_in );
719     es_format_Clean( &p_filter->fmt_out );
720
721     vlc_object_destroy( p_filter );
722 }