]> git.sesse.net Git - vlc/blob - src/misc/image.c
fourcc: add avc3
[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_PNG,               "png" },
507     { VLC_CODEC_PGM,               "pgm" },
508     { VLC_CODEC_PGMYUV,            "pgmyuv" },
509     { VLC_FOURCC('p','b','m',' '), "pbm" },
510     { VLC_FOURCC('p','a','m',' '), "pam" },
511     { VLC_CODEC_TARGA,             "tga" },
512     { VLC_CODEC_BMP,               "bmp" },
513     { VLC_CODEC_PNM,               "pnm" },
514     { VLC_FOURCC('x','p','m',' '), "xpm" },
515     { VLC_FOURCC('x','c','f',' '), "xcf" },
516     { VLC_CODEC_PCX,               "pcx" },
517     { VLC_CODEC_GIF,               "gif" },
518     { VLC_CODEC_SVG,               "svg" },
519     { VLC_CODEC_TIFF,              "tif" },
520     { VLC_CODEC_TIFF,              "tiff" },
521     { VLC_FOURCC('l','b','m',' '), "lbm" },
522     { VLC_CODEC_PPM,               "ppm" },
523 };
524
525 vlc_fourcc_t image_Type2Fourcc( const char *psz_type )
526 {
527     for( unsigned i = 0; i < ARRAY_SIZE(ext_table); i++ )
528         if( !strcasecmp( ext_table[i].psz_ext, psz_type ) )
529             return ext_table[i].i_codec;
530
531     return 0;
532 }
533
534 vlc_fourcc_t image_Ext2Fourcc( const char *psz_name )
535 {
536     psz_name = strrchr( psz_name, '.' );
537     if( !psz_name ) return 0;
538     psz_name++;
539
540     return image_Type2Fourcc( psz_name );
541 }
542
543 /*
544 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
545 {
546     for( unsigned i = 0; i < ARRAY_SIZE(ext_table); i++ )
547         if( ext_table[i].i_codec == i_codec )
548             return ext_table[i].psz_ext;
549
550     return NULL;
551 }
552 */
553
554 static const struct
555 {
556     vlc_fourcc_t i_codec;
557     const char *psz_mime;
558 } mime_table[] =
559 {
560     { VLC_CODEC_BMP,               "image/bmp" },
561     { VLC_CODEC_BMP,               "image/x-bmp" },
562     { VLC_CODEC_BMP,               "image/x-bitmap" },
563     { VLC_CODEC_BMP,               "image/x-ms-bmp" },
564     { VLC_CODEC_PNM,               "image/x-portable-anymap" },
565     { VLC_CODEC_PNM,               "image/x-portable-bitmap" },
566     { VLC_CODEC_PNM,               "image/x-portable-graymap" },
567     { VLC_CODEC_PNM,               "image/x-portable-pixmap" },
568     { VLC_CODEC_GIF,               "image/gif" },
569     { VLC_CODEC_JPEG,              "image/jpeg" },
570     { VLC_CODEC_PCX,               "image/pcx" },
571     { VLC_CODEC_PNG,               "image/png" },
572     { VLC_CODEC_SVG,               "image/svg+xml" },
573     { VLC_CODEC_TIFF,              "image/tiff" },
574     { VLC_CODEC_TARGA,             "image/x-tga" },
575     { VLC_FOURCC('x','p','m',' '), "image/x-xpixmap" },
576     { 0, NULL }
577 };
578
579 vlc_fourcc_t image_Mime2Fourcc( const char *psz_mime )
580 {
581     int i;
582     for( i = 0; mime_table[i].i_codec; i++ )
583         if( !strcmp( psz_mime, mime_table[i].psz_mime ) )
584             return mime_table[i].i_codec;
585     return 0;
586 }
587
588 static int video_update_format( decoder_t *p_dec )
589 {
590     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
591     return 0;
592 }
593
594 static picture_t *video_new_buffer( decoder_t *p_dec )
595 {
596     return picture_NewFromFormat( &p_dec->fmt_out.video );
597 }
598
599 static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
600 {
601     decoder_t *p_dec;
602
603     p_dec = vlc_custom_create( p_this, sizeof( *p_dec ), "image decoder" );
604     if( p_dec == NULL )
605         return NULL;
606
607     p_dec->p_module = NULL;
608     es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
609     es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
610     p_dec->fmt_in.video = *fmt;
611     p_dec->b_pace_control = true;
612
613     p_dec->pf_vout_format_update = video_update_format;
614     p_dec->pf_vout_buffer_new = video_new_buffer;
615
616     /* Find a suitable decoder module */
617     p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
618     if( !p_dec->p_module )
619     {
620         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
621                  "VLC probably does not support this image format.",
622                  (char*)&p_dec->fmt_in.i_codec );
623
624         DeleteDecoder( p_dec );
625         return NULL;
626     }
627
628     return p_dec;
629 }
630
631 static void DeleteDecoder( decoder_t * p_dec )
632 {
633     if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
634
635     es_format_Clean( &p_dec->fmt_in );
636     es_format_Clean( &p_dec->fmt_out );
637
638     if( p_dec->p_description )
639         vlc_meta_Delete( p_dec->p_description );
640
641     vlc_object_release( p_dec );
642     p_dec = NULL;
643 }
644
645 static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
646                                  video_format_t *fmt_out )
647 {
648     encoder_t *p_enc;
649
650     p_enc = sout_EncoderCreate( p_this );
651     if( p_enc == NULL )
652         return NULL;
653
654     p_enc->p_module = NULL;
655     es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
656     p_enc->fmt_in.video = *fmt_in;
657
658     if( p_enc->fmt_in.video.i_visible_width == 0 ||
659         p_enc->fmt_in.video.i_visible_height == 0 )
660     {
661         if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
662         {
663             p_enc->fmt_in.video.i_width = fmt_out->i_width;
664             p_enc->fmt_in.video.i_height = fmt_out->i_height;
665
666             if( fmt_out->i_visible_width > 0 &&
667                 fmt_out->i_visible_height > 0 )
668             {
669                 p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
670                 p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
671             }
672             else
673             {
674                 p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
675                 p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
676             }
677         }
678         else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
679                  fmt_out->i_sar_num * fmt_in->i_sar_den !=
680                  fmt_out->i_sar_den * fmt_in->i_sar_num )
681         {
682             p_enc->fmt_in.video.i_width =
683                 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
684                 fmt_in->i_sar_den / fmt_out->i_sar_num;
685             p_enc->fmt_in.video.i_visible_width =
686                 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
687                 fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
688         }
689     }
690
691     p_enc->fmt_in.video.i_frame_rate = 25;
692     p_enc->fmt_in.video.i_frame_rate_base = 1;
693
694     es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
695     p_enc->fmt_out.video = *fmt_out;
696     p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
697     p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
698
699     /* Find a suitable decoder module */
700     p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
701     if( !p_enc->p_module )
702     {
703         msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
704                  "VLC probably does not support this image format.",
705                  (char*)&p_enc->fmt_out.i_codec );
706
707         DeleteEncoder( p_enc );
708         return NULL;
709     }
710     p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
711
712     return p_enc;
713 }
714
715 static void DeleteEncoder( encoder_t * p_enc )
716 {
717     if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
718
719     es_format_Clean( &p_enc->fmt_in );
720     es_format_Clean( &p_enc->fmt_out );
721
722     vlc_object_release( p_enc );
723     p_enc = NULL;
724 }
725
726 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
727                                video_format_t *p_fmt_out )
728 {
729     filter_t *p_filter;
730
731     p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" );
732     p_filter->owner.video.buffer_new =
733         (picture_t *(*)(filter_t *))video_new_buffer;
734
735     p_filter->fmt_in = *p_fmt_in;
736     p_filter->fmt_out = *p_fmt_in;
737     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
738     p_filter->fmt_out.video = *p_fmt_out;
739     p_filter->p_module = module_need( p_filter, "video filter2", NULL, false );
740
741     if( !p_filter->p_module )
742     {
743         msg_Dbg( p_filter, "no video filter found" );
744         DeleteFilter( p_filter );
745         return NULL;
746     }
747
748     return p_filter;
749 }
750
751 static void DeleteFilter( filter_t * p_filter )
752 {
753     if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
754
755     es_format_Clean( &p_filter->fmt_in );
756     es_format_Clean( &p_filter->fmt_out );
757
758     vlc_object_release( p_filter );
759 }