]> git.sesse.net Git - vlc/blob - src/misc/image.c
* src/misc/image.c: no need to restart a filter when only the image size changes.
[vlc] / src / misc / image.c
1 /*****************************************************************************
2  * image.c : wrapper for image reading/writing facilities
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
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 decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
48 static void DeleteDecoder( decoder_t * );
49 static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
50                                video_format_t * );
51 static void DeleteFilter( filter_t * );
52
53 static vlc_fourcc_t Ext2Fourcc( const char * );
54 static const char *Fourcc2Ext( vlc_fourcc_t );
55
56 /**
57  * Create an image_handler_t instance
58  *
59  */
60 image_handler_t *__image_HandlerCreate( vlc_object_t *p_this )
61 {
62     image_handler_t *p_image = malloc( sizeof(image_handler_t) );
63
64     memset( p_image, 0, sizeof(image_handler_t) );
65     p_image->p_parent = p_this;
66
67     p_image->pf_read = ImageRead;
68     p_image->pf_read_url = ImageReadUrl;
69     p_image->pf_write = ImageWrite;
70     p_image->pf_write_url = ImageWriteUrl;
71
72     return p_image;
73 }
74
75 /**
76  * Delete the image_handler_t instance
77  *
78  */
79 void image_HandlerDelete( image_handler_t *p_image )
80 {
81     if( !p_image ) return;
82
83     if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
84     if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
85
86     free( p_image );
87 }
88
89 /**
90  * Read an image
91  *
92  */
93
94 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
95                              video_format_t *p_fmt_in,
96                              video_format_t *p_fmt_out )
97 {
98     picture_t *p_pic;
99
100     /* Check if we can reuse the current decoder */
101     if( p_image->p_dec &&
102         p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
103     {
104         DeleteDecoder( p_image->p_dec );
105         p_image->p_dec = 0;
106     }
107
108     /* Start a decoder */
109     if( !p_image->p_dec )
110     {
111         p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
112         if( !p_image->p_dec ) return NULL;
113     }
114
115     p_block->i_pts = p_block->i_dts = mdate();
116     p_pic = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
117     p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block );
118
119     if( !p_pic )
120     {
121         msg_Dbg( p_image->p_parent, "no image decoded" );
122         return 0;
123     }
124
125     if( !p_fmt_out->i_chroma )
126         p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
127     if( !p_fmt_out->i_width )
128         p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
129     if( !p_fmt_out->i_height )
130         p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
131
132     /* Check if we need chroma conversion or resizing */
133     if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
134         p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
135         p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
136     {
137         if( p_image->p_filter )
138         if( p_image->p_filter->fmt_in.video.i_chroma !=
139             p_image->p_dec->fmt_out.video.i_chroma ||
140             p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
141         {
142             /* We need to restart a new filter */
143             DeleteFilter( p_image->p_filter );
144             p_image->p_filter = 0;
145         }
146
147         /* Start a filter */
148         if( !p_image->p_filter )
149         {
150             p_image->p_filter =
151                 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
152                               p_fmt_out );
153
154             if( !p_image->p_filter )
155             {
156                 p_pic->pf_release( p_pic );
157                 return NULL;
158             }
159         }
160         else
161         {
162             /* Filters should handle on-the-fly size changes */
163             p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
164             p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
165             p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
166             p_image->p_filter->fmt_out.video = *p_fmt_out;
167         }
168
169         p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
170         *p_fmt_out = p_image->p_filter->fmt_out.video;
171     }
172     else *p_fmt_out = p_image->p_dec->fmt_out.video;
173
174     return p_pic;
175 }
176
177 static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
178                                 video_format_t *p_fmt_in,
179                                 video_format_t *p_fmt_out )
180 {
181     block_t *p_block;
182     picture_t *p_pic;
183     FILE *file;
184     int i_size;
185
186     file = fopen( psz_url, "rb" );
187     if( !file )
188     {
189         msg_Dbg( p_image->p_parent, "could not open file %s for reading",
190                  psz_url );
191         return NULL;
192     }
193
194     fseek( file, 0, SEEK_END );
195     i_size = ftell( file );
196     fseek( file, 0, SEEK_SET );
197
198     p_block = block_New( p_image->p_parent, i_size );
199     fread( p_block->p_buffer, sizeof(char), i_size, file );
200     fclose( file );
201
202     if( !p_fmt_in->i_chroma )
203     {
204         /* Try to guess format from file name */
205         p_fmt_in->i_chroma = Ext2Fourcc( psz_url );
206     }
207
208     p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
209
210     return p_pic;
211 }
212
213 /**
214  * Write an image
215  *
216  */
217
218 static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
219                             video_format_t *p_fmt_in,
220                             video_format_t *p_fmt_out )
221 {
222     return NULL;
223 }
224
225 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
226                           video_format_t *p_fmt_in, video_format_t *p_fmt_out,
227                           const char *psz_url )
228 {
229     return VLC_EGENERIC;
230 }
231
232 /**
233  * Misc functions
234  *
235  */
236 static struct
237 {
238     vlc_fourcc_t i_codec;
239     char *psz_ext;
240
241 } ext_table[] =
242 {
243     { VLC_FOURCC('j','p','e','g'), "jpeg" },
244     { VLC_FOURCC('j','p','e','g'), "jpg"  },
245     { VLC_FOURCC('l','j','p','g'), "ljpg" },
246     { VLC_FOURCC('p','n','g',' '), "png" },
247     { VLC_FOURCC('p','g','m',' '), "pgm" },
248     { VLC_FOURCC('p','g','m','y'), "pgmyuv" },
249     { VLC_FOURCC('p','b','m',' '), "pbm" },
250     { VLC_FOURCC('p','a','m',' '), "pam" },
251     { 0, NULL }
252 };
253
254 static vlc_fourcc_t Ext2Fourcc( const char *psz_name )
255 {
256     int i;
257
258     psz_name = strrchr( psz_name, '.' );
259     if( !psz_name ) return 0;
260     psz_name++;
261
262     for( i = 0; ext_table[i].i_codec; i++ )
263     {
264         int j;
265         for( j = 0; toupper(ext_table[i].psz_ext[j]) == toupper(psz_name[j]);
266              j++ )
267         {
268             if( !ext_table[i].psz_ext[j] && !psz_name[j] )
269                 return ext_table[i].i_codec;
270         }
271     }
272
273     return 0;
274 }
275
276 static const char *Fourcc2Ext( vlc_fourcc_t i_codec )
277 {
278     int i;
279
280     for( i = 0; ext_table[i].i_codec != 0; i++ )
281     {
282         if( ext_table[i].i_codec == i_codec ) return ext_table[i].psz_ext;
283     }
284
285     return NULL;
286 }
287
288 static void video_release_buffer( picture_t *p_pic )
289 {
290     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
291     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
292     if( p_pic ) free( p_pic );
293 }
294
295 static picture_t *video_new_buffer( decoder_t *p_dec )
296 {
297     picture_t *p_pic = malloc( sizeof(picture_t) );
298
299     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
300     vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
301                           p_dec->fmt_out.video.i_chroma,
302                           p_dec->fmt_out.video.i_width,
303                           p_dec->fmt_out.video.i_height,
304                           p_dec->fmt_out.video.i_aspect );
305
306     if( !p_pic->i_planes )
307     {
308         free( p_pic );
309         return 0;
310     }
311
312     p_pic->pf_release = video_release_buffer;
313     p_pic->i_status = RESERVED_PICTURE;
314     p_pic->p_sys = NULL;
315
316     return p_pic;
317 }
318
319 static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
320 {
321     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
322     if( p_pic && p_pic->p_sys ) free( p_pic->p_sys );
323     if( p_pic ) free( p_pic );
324 }
325
326 static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
327 {
328 }
329
330 static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
331 {
332 }
333
334 static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
335 {
336     decoder_t *p_dec;
337     static es_format_t null_es_format = {0};
338
339     p_dec = vlc_object_create( p_this, VLC_OBJECT_DECODER );
340     if( p_dec == NULL )
341     {
342         msg_Err( p_this, "out of memory" );
343         return NULL;
344     }
345
346     p_dec->p_module = NULL;
347     es_format_Copy( &p_dec->fmt_in, &null_es_format );
348     es_format_Copy( &p_dec->fmt_out, &null_es_format );
349     p_dec->fmt_in.video = *fmt;
350     p_dec->fmt_in.i_cat = VIDEO_ES;
351     p_dec->fmt_in.i_codec = fmt->i_chroma;
352     p_dec->b_pace_control = VLC_TRUE;
353
354     p_dec->pf_vout_buffer_new = video_new_buffer;
355     p_dec->pf_vout_buffer_del = video_del_buffer;
356     p_dec->pf_picture_link    = video_link_picture;
357     p_dec->pf_picture_unlink  = video_unlink_picture;
358
359     vlc_object_attach( p_dec, p_this );
360
361     /* Find a suitable decoder module */
362     p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
363     if( !p_dec->p_module )
364     {
365         msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
366                  "VLC probably does not support this image format.",
367                  (char*)&p_dec->fmt_in.i_codec );
368
369         DeleteDecoder( p_dec );
370         return NULL;
371     }
372
373     return p_dec;
374 }
375
376 static void DeleteDecoder( decoder_t * p_dec )
377 {
378     vlc_object_detach( p_dec );
379
380     if( p_dec->p_module ) module_Unneed( p_dec, p_dec->p_module );
381
382     es_format_Clean( &p_dec->fmt_in );
383     es_format_Clean( &p_dec->fmt_out );
384
385     vlc_object_destroy( p_dec );
386 }
387
388 static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
389                                video_format_t *p_fmt_out )
390 {
391     filter_t *p_filter;
392
393     p_filter = vlc_object_create( p_this, VLC_OBJECT_FILTER );
394     vlc_object_attach( p_filter, p_this );
395
396     p_filter->pf_vout_buffer_new =
397         (picture_t *(*)(filter_t *))video_new_buffer;
398     p_filter->pf_vout_buffer_del =
399         (void (*)(filter_t *, picture_t *))video_del_buffer;
400
401     p_filter->fmt_in = *p_fmt_in;
402     p_filter->fmt_out = *p_fmt_in;
403     p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
404     p_filter->fmt_out.video = *p_fmt_out;
405     p_filter->p_module = module_Need( p_filter, "video filter2", 0, 0 );
406
407     if( !p_filter->p_module )
408     {
409         msg_Dbg( p_filter, "no video filter found" );
410         DeleteFilter( p_filter );
411         return NULL;
412     }
413
414     return p_filter;
415 }
416
417 static void DeleteFilter( filter_t * p_filter )
418 {
419     vlc_object_detach( p_filter );
420
421     if( p_filter->p_module ) module_Unneed( p_filter, p_filter->p_module );
422
423     es_format_Clean( &p_filter->fmt_in );
424     es_format_Clean( &p_filter->fmt_out );
425
426     vlc_object_destroy( p_filter );
427 }