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