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