]> git.sesse.net Git - vlc/blob - src/misc/image.c
* src/misc/image.c: New image_Filter call to apply a filter on a picture_t
[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., 59 Temple Place - Suite 330, Boston, MA  02111, 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
38 static picture_t *ImageRead( image_handler_t *, block_t *,
39                              video_format_t *, video_format_t * );
40 static picture_t *ImageReadUrl( image_handler_t *, const char *,
41                                 video_format_t *, video_format_t * );
42 static block_t *ImageWrite( image_handler_t *, picture_t *,
43                             video_format_t *, video_format_t * );
44 static int ImageWriteUrl( image_handler_t *, picture_t *,
45                           video_format_t *, video_format_t *, const char * );
46
47 static picture_t *ImageConvert( image_handler_t *, picture_t *,
48                                 video_format_t *, video_format_t * );
49 static picture_t *ImageFilter( image_handler_t *, picture_t *,
50                                video_format_t *, const char *psz_module );
51
52 static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
53 static void DeleteDecoder( decoder_t * );
54 static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
55                                  video_format_t * );
56 static void DeleteEncoder( encoder_t * );
57 static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
58                                video_format_t *, const char * );
59 static void DeleteFilter( filter_t * );
60
61 static vlc_fourcc_t Ext2Fourcc( const char * );
62 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
63
64 /**
65  * Create an image_handler_t instance
66  *
67  */
68 image_handler_t *__image_HandlerCreate( vlc_object_t *p_this )
69 {
70     image_handler_t *p_image = malloc( sizeof(image_handler_t) );
71
72     memset( p_image, 0, sizeof(image_handler_t) );
73     p_image->p_parent = p_this;
74
75     p_image->pf_read = ImageRead;
76     p_image->pf_read_url = ImageReadUrl;
77     p_image->pf_write = ImageWrite;
78     p_image->pf_write_url = ImageWriteUrl;
79     p_image->pf_convert = ImageConvert;
80     p_image->pf_filter = ImageFilter;
81
82     return p_image;
83 }
84
85 /**
86  * Delete the image_handler_t instance
87  *
88  */
89 void image_HandlerDelete( image_handler_t *p_image )
90 {
91     if( !p_image ) return;
92
93     if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
94     if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
95     if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
96
97     free( p_image );
98 }
99
100 /**
101  * Read an image
102  *
103  */
104
105 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
106                              video_format_t *p_fmt_in,
107                              video_format_t *p_fmt_out )
108 {
109     picture_t *p_pic = NULL, *p_tmp;
110
111     /* Check if we can reuse the current decoder */
112     if( p_image->p_dec &&
113         p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
114     {
115         DeleteDecoder( p_image->p_dec );
116         p_image->p_dec = 0;
117     }
118
119     /* Start a decoder */
120     if( !p_image->p_dec )
121     {
122         p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
123         if( !p_image->p_dec ) return NULL;
124     }
125
126     p_block->i_pts = p_block->i_dts = mdate();
127     p_pic = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
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 = 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_pif;
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_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
314         p_pic->pf_release = pf_release;
315         p_pic = p_pif;
316     }
317
318     p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
319
320     if( !p_block )
321     {
322         msg_Dbg( p_image->p_parent, "no image encoded" );
323         return 0;
324     }
325
326     return p_block;
327 }
328
329 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
330                           video_format_t *p_fmt_in, video_format_t *p_fmt_out,
331                           const char *psz_url )
332 {
333     block_t *p_block;
334     FILE *file;
335
336     if( !p_fmt_out->i_chroma )
337     {
338         /* Try to guess format from file name */
339         p_fmt_out->i_chroma = Ext2Fourcc( psz_url );
340     }
341
342     file = fopen( psz_url, "wb" );
343     if( !file )
344     {
345         msg_Dbg( p_image->p_parent, "could not open file %s for writing",
346                  psz_url );
347         return VLC_EGENERIC;
348     }
349
350     p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
351
352     if( p_block )
353     {
354         fwrite( p_block->p_buffer, sizeof(char), p_block->i_buffer, file );
355         block_Release( p_block );
356     }
357
358     fclose( file );
359
360     return p_block ? VLC_SUCCESS : VLC_EGENERIC;
361 }
362
363 /**
364  * Convert an image to a different format
365  *
366  */
367
368 static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
369                                 video_format_t *p_fmt_in,
370                                 video_format_t *p_fmt_out )
371 {
372     void (*pf_release)( picture_t * );
373     picture_t *p_pif;
374
375     if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
376         p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
377         p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
378         p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
379     {
380         p_fmt_out->i_width =
381             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
382             p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
383         p_fmt_out->i_visible_width =
384             p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
385             p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
386             p_fmt_out->i_sar_num;
387     }
388
389     if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
390     if( !p_fmt_out->i_width )
391         p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
392     if( !p_fmt_out->i_height )
393         p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
394     if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
395     if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
396     if( !p_fmt_out->i_aspect ) p_fmt_out->i_aspect = p_fmt_in->i_aspect;
397
398     if( p_image->p_filter )
399     if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
400         p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
401     {
402         /* We need to restart a new filter */
403         DeleteFilter( p_image->p_filter );
404         p_image->p_filter = 0;
405     }
406
407     /* Start a filter */
408     if( !p_image->p_filter )
409     {
410         es_format_t fmt_in;
411         es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
412         fmt_in.video = *p_fmt_in;
413
414         p_image->p_filter =
415             CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out, NULL );
416
417         if( !p_image->p_filter )
418         {
419             return NULL;
420         }
421     }
422     else
423     {
424         /* Filters should handle on-the-fly size changes */
425         p_image->p_filter->fmt_in.video = *p_fmt_in;
426         p_image->p_filter->fmt_out.video = *p_fmt_out;
427     }
428
429     pf_release = p_pic->pf_release;
430     p_pic->pf_release = PicRelease; /* Small hack */
431     p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
432     p_pic->pf_release = pf_release;
433
434     if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
435         p_fmt_in->i_width == p_fmt_out->i_width &&
436         p_fmt_in->i_height == p_fmt_out->i_height )
437     {
438         /* Duplicate image */
439         p_pif = p_image->p_filter->pf_vout_buffer_new( p_image->p_filter );
440         if( p_pif ) vout_CopyPicture( p_image->p_parent, p_pif, p_pic );
441     }
442
443     return p_pif;
444 }
445
446 /**
447  * Filter an image with a psz_module filter
448  *
449  */
450
451 static picture_t *ImageFilter( image_handler_t *p_image, picture_t *p_pic,
452                                video_format_t *p_fmt, const char *psz_module )
453 {
454     void (*pf_release)( picture_t * );
455     picture_t *p_pif;
456
457     /* Start a filter */
458     if( !p_image->p_filter )
459     {
460         es_format_t fmt;
461         es_format_Init( &fmt, VIDEO_ES, p_fmt->i_chroma );
462         fmt.video = *p_fmt;
463
464         p_image->p_filter =
465             CreateFilter( p_image->p_parent, &fmt, &fmt.video, psz_module );
466
467         if( !p_image->p_filter )
468         {
469             return NULL;
470         }
471     }
472     else
473     {
474         /* Filters should handle on-the-fly size changes */
475         p_image->p_filter->fmt_in.video = *p_fmt;
476         p_image->p_filter->fmt_out.video = *p_fmt;
477     }
478
479     pf_release = p_pic->pf_release;
480     p_pic->pf_release = PicRelease; /* Small hack */
481     p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
482     p_pic->pf_release = pf_release;
483
484     return p_pif;
485 }
486
487 /**
488  * Misc functions
489  *
490  */
491 static struct
492 {
493     vlc_fourcc_t i_codec;
494     char *psz_ext;
495
496 } ext_table[] =
497 {
498     { VLC_FOURCC('j','p','e','g'), "jpeg" },
499     { VLC_FOURCC('j','p','e','g'), "jpg"  },
500     { VLC_FOURCC('l','j','p','g'), "ljpg" },
501     { VLC_FOURCC('p','n','g',' '), "png" },
502     { VLC_FOURCC('p','g','m',' '), "pgm" },
503     { VLC_FOURCC('p','g','m','y'), "pgmyuv" },
504     { VLC_FOURCC('p','b','m',' '), "pbm" },
505     { VLC_FOURCC('p','a','m',' '), "pam" },
506     { VLC_FOURCC('t','g','a',' '), "tga" },
507     { VLC_FOURCC('b','m','p',' '), "bmp" },
508     { VLC_FOURCC('p','n','m',' '), "pnm" },
509     { VLC_FOURCC('x','p','m',' '), "xpm" },
510     { VLC_FOURCC('x','c','f',' '), "xcf" },
511     { VLC_FOURCC('p','c','x',' '), "pcx" },
512     { VLC_FOURCC('g','i','f',' '), "gif" },
513     { VLC_FOURCC('t','i','f','f'), "tif" },
514     { VLC_FOURCC('t','i','f','f'), "tiff" },
515     { VLC_FOURCC('l','b','m',' '), "lbm" },
516     { 0, NULL }
517 };
518
519 static vlc_fourcc_t Ext2Fourcc( const char *psz_name )
520 {
521     int i;
522
523     psz_name = strrchr( psz_name, '.' );
524     if( !psz_name ) return 0;
525     psz_name++;
526
527     for( i = 0; ext_table[i].i_codec; i++ )
528     {
529         int j;
530         for( j = 0; toupper(ext_table[i].psz_ext[j]) == toupper(psz_name[j]);
531              j++ )
532         {
533             if( !ext_table[i].psz_ext[j] && !psz_name[j] )
534                 return ext_table[i].i_codec;
535         }
536     }
537
538     return 0;
539 }
540
541 /*
542 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
543 {
544     int i;
545
546     for( i = 0; ext_table[i].i_codec != 0; i++ )
547     {
548         if( ext_table[i].i_codec == i_codec ) return ext_table[i].psz_ext;
549     }
550
551     return NULL;
552 }
553 */
554
555 static void video_release_buffer( picture_t *p_pic )
556 {
557     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
558     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
559     if( p_pic ) free( p_pic );
560 }
561
562 static picture_t *video_new_buffer( decoder_t *p_dec )
563 {
564     picture_t *p_pic = malloc( sizeof(picture_t) );
565
566     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
567     vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
568                           p_dec->fmt_out.video.i_chroma,
569                           p_dec->fmt_out.video.i_width,
570                           p_dec->fmt_out.video.i_height,
571                           p_dec->fmt_out.video.i_aspect );
572
573     if( !p_pic->i_planes )
574     {
575         free( p_pic );
576         return 0;
577     }
578
579     p_pic->pf_release = video_release_buffer;
580     p_pic->i_status = RESERVED_PICTURE;
581     p_pic->p_sys = NULL;
582
583     return p_pic;
584 }
585
586 static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
587 {
588     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
589     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
590     if( p_pic ) free( p_pic );
591 }
592
593 static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
594 {
595 }
596
597 static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
598 {
599 }
600
601 static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
602 {
603     decoder_t *p_dec;
604
605     p_dec = vlc_object_create( p_this, VLC_OBJECT_DECODER );
606     if( p_dec == NULL )
607     {
608         msg_Err( p_this, "out of memory" );
609         return NULL;
610     }
611
612     p_dec->p_module = NULL;
613     es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
614     es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
615     p_dec->fmt_in.video = *fmt;
616     p_dec->b_pace_control = VLC_TRUE;
617
618     p_dec->pf_vout_buffer_new = video_new_buffer;
619     p_dec->pf_vout_buffer_del = video_del_buffer;
620     p_dec->pf_picture_link    = video_link_picture;
621     p_dec->pf_picture_unlink  = video_unlink_picture;
622
623     vlc_object_attach( p_dec, p_this );
624
625     /* Find a suitable decoder module */
626     p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
627     if( !p_dec->p_module )
628     {
629         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
630                  "VLC probably does not support this image format.",
631                  (char*)&p_dec->fmt_in.i_codec );
632
633         DeleteDecoder( p_dec );
634         return NULL;
635     }
636
637     return p_dec;
638 }
639
640 static void DeleteDecoder( decoder_t * p_dec )
641 {
642     vlc_object_detach( p_dec );
643
644     if( p_dec->p_module ) module_Unneed( p_dec, p_dec->p_module );
645
646     es_format_Clean( &p_dec->fmt_in );
647     es_format_Clean( &p_dec->fmt_out );
648
649     vlc_object_destroy( p_dec );
650 }
651
652 static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
653                                  video_format_t *fmt_out )
654 {
655     encoder_t *p_enc;
656
657     p_enc = vlc_object_create( p_this, VLC_OBJECT_ENCODER );
658     if( p_enc == NULL )
659     {
660         msg_Err( p_this, "out of memory" );
661         return NULL;
662     }
663
664     p_enc->p_module = NULL;
665     es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
666     p_enc->fmt_in.video = *fmt_in;
667     if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
668     {
669         p_enc->fmt_in.video.i_width = fmt_out->i_width;
670         p_enc->fmt_in.video.i_height = fmt_out->i_height;
671
672         if( fmt_out->i_visible_width > 0 &&
673             fmt_out->i_visible_height > 0 )
674         {
675             p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
676             p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
677         }
678         else
679         {
680             p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
681             p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
682         }
683     }
684     else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
685              fmt_out->i_sar_num * fmt_in->i_sar_den !=
686              fmt_out->i_sar_den * fmt_in->i_sar_num )
687     {
688         p_enc->fmt_in.video.i_width =
689             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
690             fmt_in->i_sar_den / fmt_out->i_sar_num;
691         p_enc->fmt_in.video.i_visible_width =
692             fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
693             fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
694     }
695
696     p_enc->fmt_in.video.i_frame_rate = 25;
697     p_enc->fmt_in.video.i_frame_rate_base = 1;
698
699     es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
700     p_enc->fmt_out.video = *fmt_out;
701     p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
702     p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
703
704     vlc_object_attach( p_enc, p_this );
705
706     /* Find a suitable decoder module */
707     p_enc->p_module = module_Need( p_enc, "encoder", 0, 0 );
708     if( !p_enc->p_module )
709     {
710         msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
711                  "VLC probably does not support this image format.",
712                  (char*)&p_enc->fmt_out.i_codec );
713
714         DeleteEncoder( p_enc );
715         return NULL;
716     }
717     p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
718
719     return p_enc;
720 }
721
722 static void DeleteEncoder( encoder_t * p_enc )
723 {
724     vlc_object_detach( p_enc );
725
726     if( p_enc->p_module ) module_Unneed( p_enc, p_enc->p_module );
727
728     es_format_Clean( &p_enc->fmt_in );
729     es_format_Clean( &p_enc->fmt_out );
730
731     vlc_object_destroy( p_enc );
732 }
733
734 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
735                                video_format_t *p_fmt_out,
736                                const char *psz_module )
737 {
738     filter_t *p_filter;
739
740     p_filter = vlc_object_create( p_this, VLC_OBJECT_FILTER );
741     vlc_object_attach( p_filter, p_this );
742
743     p_filter->pf_vout_buffer_new =
744         (picture_t *(*)(filter_t *))video_new_buffer;
745     p_filter->pf_vout_buffer_del =
746         (void (*)(filter_t *, picture_t *))video_del_buffer;
747
748     p_filter->fmt_in = *p_fmt_in;
749     p_filter->fmt_out = *p_fmt_in;
750     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
751     p_filter->fmt_out.video = *p_fmt_out;
752     p_filter->p_module = module_Need( p_filter, "video filter2", psz_module,
753                                       0 );
754
755     if( !p_filter->p_module )
756     {
757         msg_Dbg( p_filter, "no video filter found" );
758         DeleteFilter( p_filter );
759         return NULL;
760     }
761
762     return p_filter;
763 }
764
765 static void DeleteFilter( filter_t * p_filter )
766 {
767     vlc_object_detach( p_filter );
768
769     if( p_filter->p_module ) module_Unneed( p_filter, p_filter->p_module );
770
771     es_format_Clean( &p_filter->fmt_in );
772     es_format_Clean( &p_filter->fmt_out );
773
774     vlc_object_destroy( p_filter );
775 }