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