]> git.sesse.net Git - vlc/blob - src/misc/image.c
do everything with the stream functions (no more fopen)
[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     if( !p_stream )
213     {
214         msg_Dbg( p_image->p_parent, "could not open %s for reading",
215                  psz_url );
216         return NULL;
217     }
218
219     i_size = stream_Size( p_stream );
220
221     p_block = block_New( p_image->p_parent, i_size );
222
223     stream_Read( p_stream, p_block->p_buffer, i_size );
224     stream_Delete( p_stream );
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 }