Dshow: relicense to LGPL
[vlc.git] / src / misc / image.c
bloba1c5b1c346679621b0e7212a919e2c2f366952a4
1 /*****************************************************************************
2 * image.c : wrapper for image reading/writing facilities
3 *****************************************************************************
4 * Copyright (C) 2004-2007 VLC authors and VideoLAN
5 * $Id$
7 * Author: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /**
25 * \file
26 * This file contains the functions to handle the image_handler_t type
29 /*****************************************************************************
30 * Preamble
31 *****************************************************************************/
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
37 #include <errno.h>
38 #include <limits.h>
40 #include <vlc_common.h>
41 #include <vlc_codec.h>
42 #include <vlc_meta.h>
43 #include <vlc_filter.h>
44 #include <vlc_es.h>
45 #include <vlc_image.h>
46 #include <vlc_stream.h>
47 #include <vlc_fs.h>
48 #include <vlc_sout.h>
49 #include <libvlc.h>
50 #include <vlc_modules.h>
52 struct decoder_owner
54 decoder_t dec;
55 image_handler_t *p_image;
58 static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
60 return container_of( p_dec, struct decoder_owner, dec );
63 static picture_t *ImageRead( image_handler_t *, block_t *,
64 const video_format_t *, video_format_t * );
65 static picture_t *ImageReadUrl( image_handler_t *, const char *,
66 video_format_t *, video_format_t * );
67 static block_t *ImageWrite( image_handler_t *, picture_t *,
68 const video_format_t *, const video_format_t * );
69 static int ImageWriteUrl( image_handler_t *, picture_t *,
70 const video_format_t *, video_format_t *, const char * );
72 static picture_t *ImageConvert( image_handler_t *, picture_t *,
73 const video_format_t *, video_format_t * );
75 static decoder_t *CreateDecoder( image_handler_t *, const video_format_t * );
76 static void DeleteDecoder( decoder_t * );
77 static encoder_t *CreateEncoder( vlc_object_t *, const video_format_t *,
78 const video_format_t * );
79 static void DeleteEncoder( encoder_t * );
80 static filter_t *CreateFilter( vlc_object_t *, const es_format_t *,
81 const video_format_t * );
82 static void DeleteFilter( filter_t * );
84 vlc_fourcc_t image_Type2Fourcc( const char * );
85 vlc_fourcc_t image_Ext2Fourcc( const char * );
86 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
88 #undef image_HandlerCreate
89 /**
90 * Create an image_handler_t instance
93 image_handler_t *image_HandlerCreate( vlc_object_t *p_this )
95 image_handler_t *p_image = calloc( 1, sizeof(image_handler_t) );
96 if( !p_image )
97 return NULL;
99 p_image->p_parent = p_this;
101 p_image->pf_read = ImageRead;
102 p_image->pf_read_url = ImageReadUrl;
103 p_image->pf_write = ImageWrite;
104 p_image->pf_write_url = ImageWriteUrl;
105 p_image->pf_convert = ImageConvert;
107 p_image->outfifo = picture_fifo_New();
109 return p_image;
113 * Delete the image_handler_t instance
116 void image_HandlerDelete( image_handler_t *p_image )
118 if( !p_image ) return;
120 if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
121 if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
122 if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
124 picture_fifo_Delete( p_image->outfifo );
126 free( p_image );
127 p_image = NULL;
131 * Read an image
135 static void ImageQueueVideo( decoder_t *p_dec, picture_t *p_pic )
137 struct decoder_owner *p_owner = dec_get_owner( p_dec );
138 picture_fifo_Push( p_owner->p_image->outfifo, p_pic );
141 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
142 const video_format_t *p_fmt_in,
143 video_format_t *p_fmt_out )
145 picture_t *p_pic = NULL;
147 /* Check if we can reuse the current decoder */
148 if( p_image->p_dec &&
149 p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
151 DeleteDecoder( p_image->p_dec );
152 p_image->p_dec = 0;
155 /* Start a decoder */
156 if( !p_image->p_dec )
158 p_image->p_dec = CreateDecoder( p_image, p_fmt_in );
159 if( !p_image->p_dec )
161 block_Release(p_block);
162 return NULL;
164 if( p_image->p_dec->fmt_out.i_cat != VIDEO_ES )
166 DeleteDecoder( p_image->p_dec );
167 p_image->p_dec = NULL;
168 block_Release(p_block);
169 return NULL;
173 p_block->i_pts = p_block->i_dts = vlc_tick_now();
174 int ret = p_image->p_dec->pf_decode( p_image->p_dec, p_block );
175 if( ret == VLCDEC_SUCCESS )
177 /* Drain */
178 p_image->p_dec->pf_decode( p_image->p_dec, NULL );
180 p_pic = picture_fifo_Pop( p_image->outfifo );
182 unsigned lostcount = 0;
183 picture_t *lostpic;
184 while( ( lostpic = picture_fifo_Pop( p_image->outfifo ) ) != NULL )
186 picture_Release( lostpic );
187 lostcount++;
189 if( lostcount > 0 )
190 msg_Warn( p_image->p_parent, "Image decoder output more than one "
191 "picture (%u)", lostcount );
194 if( p_pic == NULL )
196 msg_Warn( p_image->p_parent, "no image decoded" );
197 return 0;
200 if( !p_fmt_out->i_chroma )
201 p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
202 if( !p_fmt_out->i_width && p_fmt_out->i_height )
203 p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
204 p_image->p_dec->fmt_out.video.i_sar_num *
205 p_fmt_out->i_height /
206 p_image->p_dec->fmt_out.video.i_height /
207 p_image->p_dec->fmt_out.video.i_sar_den;
209 if( !p_fmt_out->i_height && p_fmt_out->i_width )
210 p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
211 p_image->p_dec->fmt_out.video.i_sar_den *
212 p_fmt_out->i_width /
213 p_image->p_dec->fmt_out.video.i_width /
214 p_image->p_dec->fmt_out.video.i_sar_num;
215 if( !p_fmt_out->i_width )
216 p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
217 if( !p_fmt_out->i_height )
218 p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
219 if( !p_fmt_out->i_visible_width )
220 p_fmt_out->i_visible_width = p_fmt_out->i_width;
221 if( !p_fmt_out->i_visible_height )
222 p_fmt_out->i_visible_height = p_fmt_out->i_height;
224 /* Check if we need chroma conversion or resizing */
225 if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
226 p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
227 p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
229 if( p_image->p_filter )
230 if( p_image->p_filter->fmt_in.video.i_chroma !=
231 p_image->p_dec->fmt_out.video.i_chroma ||
232 p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
234 /* We need to restart a new filter */
235 DeleteFilter( p_image->p_filter );
236 p_image->p_filter = 0;
239 /* Start a filter */
240 if( !p_image->p_filter )
242 p_image->p_filter =
243 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
244 p_fmt_out );
246 if( !p_image->p_filter )
248 picture_Release( p_pic );
249 return NULL;
252 else
254 /* Filters should handle on-the-fly size changes */
255 p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
256 p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
257 p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
258 p_image->p_filter->fmt_out.video = *p_fmt_out;
261 p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
263 video_format_Clean( p_fmt_out );
264 video_format_Copy( p_fmt_out, &p_image->p_filter->fmt_out.video );
266 else
268 video_format_Clean( p_fmt_out );
269 video_format_Copy( p_fmt_out, &p_image->p_dec->fmt_out.video );
272 return p_pic;
275 static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
276 video_format_t *p_fmt_in,
277 video_format_t *p_fmt_out )
279 block_t *p_block;
280 picture_t *p_pic;
281 stream_t *p_stream = NULL;
282 uint64_t i_size;
284 p_stream = vlc_stream_NewURL( p_image->p_parent, psz_url );
286 if( !p_stream )
288 msg_Dbg( p_image->p_parent, "could not open %s for reading",
289 psz_url );
290 return NULL;
293 if( vlc_stream_GetSize( p_stream, &i_size ) || i_size > SSIZE_MAX )
295 msg_Dbg( p_image->p_parent, "could not read %s", psz_url );
296 goto error;
299 p_block = vlc_stream_Block( p_stream, i_size );
300 if( p_block == NULL )
301 goto error;
303 if( !p_fmt_in->i_chroma )
305 char *psz_mime = stream_MimeType( p_stream );
306 if( psz_mime != NULL )
308 p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
309 free( psz_mime );
312 vlc_stream_Delete( p_stream );
314 if( !p_fmt_in->i_chroma )
316 /* Try to guess format from file name */
317 p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
320 p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
322 return p_pic;
323 error:
324 vlc_stream_Delete( p_stream );
325 return NULL;
328 /* FIXME: refactor by splitting video_format_IsSimilar() API */
329 static bool BitMapFormatIsSimilar( const video_format_t *f1,
330 const video_format_t *f2 )
332 if( f1->i_chroma == VLC_CODEC_RGB15 ||
333 f1->i_chroma == VLC_CODEC_RGB16 ||
334 f1->i_chroma == VLC_CODEC_RGB24 ||
335 f1->i_chroma == VLC_CODEC_RGB32 )
337 video_format_t v1 = *f1;
338 video_format_t v2 = *f2;
340 video_format_FixRgb( &v1 );
341 video_format_FixRgb( &v2 );
343 if( v1.i_rmask != v2.i_rmask ||
344 v1.i_gmask != v2.i_gmask ||
345 v1.i_bmask != v2.i_bmask )
346 return false;
348 return true;
352 * Write an image
356 static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
357 const video_format_t *p_fmt_in,
358 const video_format_t *p_fmt_out )
360 block_t *p_block;
362 /* Check if we can reuse the current encoder */
363 if( p_image->p_enc &&
364 ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
365 p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
366 p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
368 DeleteEncoder( p_image->p_enc );
369 p_image->p_enc = 0;
372 /* Start an encoder */
373 if( !p_image->p_enc )
375 p_image->p_enc = CreateEncoder( p_image->p_parent,
376 p_fmt_in, p_fmt_out );
377 if( !p_image->p_enc ) return NULL;
380 /* Check if we need chroma conversion or resizing */
381 if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
382 p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
383 p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height ||
384 !BitMapFormatIsSimilar( &p_image->p_enc->fmt_in.video, p_fmt_in ) )
386 picture_t *p_tmp_pic;
388 if( p_image->p_filter )
389 if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
390 p_image->p_filter->fmt_out.video.i_chroma !=
391 p_image->p_enc->fmt_in.video.i_chroma ||
392 !BitMapFormatIsSimilar( &p_image->p_filter->fmt_in.video, p_fmt_in ) )
394 /* We need to restart a new filter */
395 DeleteFilter( p_image->p_filter );
396 p_image->p_filter = 0;
399 /* Start a filter */
400 if( !p_image->p_filter )
402 es_format_t fmt_in;
403 es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
404 fmt_in.video = *p_fmt_in;
406 p_image->p_filter =
407 CreateFilter( p_image->p_parent, &fmt_in,
408 &p_image->p_enc->fmt_in.video );
410 if( !p_image->p_filter )
412 return NULL;
415 else
417 /* Filters should handle on-the-fly size changes */
418 p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
419 p_image->p_filter->fmt_out.video = *p_fmt_in;
420 p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
421 p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
424 picture_Hold( p_pic );
426 p_tmp_pic =
427 p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
429 if( likely(p_tmp_pic != NULL) )
431 p_block = p_image->p_enc->pf_encode_video( p_image->p_enc,
432 p_tmp_pic );
433 picture_Release( p_tmp_pic );
435 else
436 p_block = NULL;
438 else
440 p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
443 if( !p_block )
445 msg_Dbg( p_image->p_parent, "no image encoded" );
446 return 0;
449 return p_block;
452 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
453 const video_format_t *p_fmt_in, video_format_t *p_fmt_out,
454 const char *psz_url )
456 block_t *p_block;
457 FILE *file;
459 if( !p_fmt_out->i_chroma )
461 /* Try to guess format from file name */
462 p_fmt_out->i_chroma = image_Ext2Fourcc( psz_url );
465 file = vlc_fopen( psz_url, "wb" );
466 if( !file )
468 msg_Err( p_image->p_parent, "%s: %s", psz_url, vlc_strerror_c(errno) );
469 return VLC_EGENERIC;
472 p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
474 int err = 0;
475 if( p_block )
477 if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, file ) != 1 )
478 err = errno;
479 block_Release( p_block );
482 if( fclose( file ) && !err )
483 err = errno;
485 if( err )
487 errno = err;
488 msg_Err( p_image->p_parent, "%s: %s", psz_url, vlc_strerror_c(errno) );
491 return err ? VLC_EGENERIC : VLC_SUCCESS;
495 * Convert an image to a different format
499 static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
500 const video_format_t *p_fmt_in,
501 video_format_t *p_fmt_out )
503 picture_t *p_pif;
505 if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
506 p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
507 p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
508 p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
510 p_fmt_out->i_width =
511 p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
512 p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
513 p_fmt_out->i_visible_width =
514 p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
515 p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
516 p_fmt_out->i_sar_num;
519 if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
520 if( !p_fmt_out->i_width )
521 p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
522 if( !p_fmt_out->i_height )
523 p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
524 if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
525 if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
527 if( p_image->p_filter )
528 if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
529 p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
531 /* We need to restart a new filter */
532 DeleteFilter( p_image->p_filter );
533 p_image->p_filter = NULL;
536 /* Start a filter */
537 if( !p_image->p_filter )
539 es_format_t fmt_in;
540 es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
541 fmt_in.video = *p_fmt_in;
543 p_image->p_filter =
544 CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out );
546 if( !p_image->p_filter )
548 return NULL;
551 else
553 /* Filters should handle on-the-fly size changes */
554 p_image->p_filter->fmt_in.video = *p_fmt_in;
555 p_image->p_filter->fmt_out.video = *p_fmt_out;
558 picture_Hold( p_pic );
560 p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
562 if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
563 p_fmt_in->i_width == p_fmt_out->i_width &&
564 p_fmt_in->i_height == p_fmt_out->i_height )
566 /* Duplicate image */
567 picture_Release( p_pif ); /* XXX: Better fix must be possible */
568 p_pif = filter_NewPicture( p_image->p_filter );
569 if( p_pif )
570 picture_Copy( p_pif, p_pic );
573 return p_pif;
577 * Misc functions
580 static const struct
582 vlc_fourcc_t i_codec;
583 const char psz_ext[7];
585 } ext_table[] =
587 { VLC_CODEC_JPEG, "jpeg" },
588 { VLC_CODEC_JPEG, "jpg" },
589 { VLC_CODEC_JPEGLS, "ljpg" },
590 { VLC_CODEC_BPG, "bpg" },
591 { VLC_CODEC_PNG, "png" },
592 { VLC_CODEC_PGM, "pgm" },
593 { VLC_CODEC_PGMYUV, "pgmyuv" },
594 { VLC_FOURCC('p','b','m',' '), "pbm" },
595 { VLC_FOURCC('p','a','m',' '), "pam" },
596 { VLC_CODEC_TARGA, "tga" },
597 { VLC_CODEC_BMP, "bmp" },
598 { VLC_CODEC_PNM, "pnm" },
599 { VLC_FOURCC('x','p','m',' '), "xpm" },
600 { VLC_FOURCC('x','c','f',' '), "xcf" },
601 { VLC_CODEC_PCX, "pcx" },
602 { VLC_CODEC_GIF, "gif" },
603 { VLC_CODEC_SVG, "svg" },
604 { VLC_CODEC_TIFF, "tif" },
605 { VLC_CODEC_TIFF, "tiff" },
606 { VLC_FOURCC('l','b','m',' '), "lbm" },
607 { VLC_CODEC_PPM, "ppm" },
610 vlc_fourcc_t image_Type2Fourcc( const char *psz_type )
612 for( unsigned i = 0; i < ARRAY_SIZE(ext_table); i++ )
613 if( !strcasecmp( ext_table[i].psz_ext, psz_type ) )
614 return ext_table[i].i_codec;
616 return 0;
619 vlc_fourcc_t image_Ext2Fourcc( const char *psz_name )
621 psz_name = strrchr( psz_name, '.' );
622 if( !psz_name ) return 0;
623 psz_name++;
625 return image_Type2Fourcc( psz_name );
628 static const struct
630 vlc_fourcc_t i_codec;
631 const char *psz_mime;
632 } mime_table[] =
634 { VLC_CODEC_BMP, "image/bmp" },
635 { VLC_CODEC_BMP, "image/x-bmp" },
636 { VLC_CODEC_BMP, "image/x-bitmap" },
637 { VLC_CODEC_BMP, "image/x-ms-bmp" },
638 { VLC_CODEC_PNM, "image/x-portable-anymap" },
639 { VLC_CODEC_PNM, "image/x-portable-bitmap" },
640 { VLC_CODEC_PNM, "image/x-portable-graymap" },
641 { VLC_CODEC_PNM, "image/x-portable-pixmap" },
642 { VLC_CODEC_GIF, "image/gif" },
643 { VLC_CODEC_JPEG, "image/jpeg" },
644 { VLC_CODEC_BPG, "image/bpg" },
645 { VLC_CODEC_PCX, "image/pcx" },
646 { VLC_CODEC_PNG, "image/png" },
647 { VLC_CODEC_SVG, "image/svg+xml" },
648 { VLC_CODEC_TIFF, "image/tiff" },
649 { VLC_CODEC_TARGA, "image/x-tga" },
650 { VLC_FOURCC('x','p','m',' '), "image/x-xpixmap" },
651 { 0, NULL }
654 vlc_fourcc_t image_Mime2Fourcc( const char *psz_mime )
656 for( int i = 0; mime_table[i].i_codec; i++ )
657 if( !strcmp( psz_mime, mime_table[i].psz_mime ) )
658 return mime_table[i].i_codec;
659 return 0;
662 static int video_update_format( decoder_t *p_dec )
664 p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
665 return 0;
668 static picture_t *video_new_buffer( decoder_t *p_dec )
670 return picture_NewFromFormat( &p_dec->fmt_out.video );
673 static decoder_t *CreateDecoder( image_handler_t *p_image, const video_format_t *fmt )
675 decoder_t *p_dec;
676 struct decoder_owner *p_owner;
678 p_owner = vlc_custom_create( p_image->p_parent, sizeof( *p_owner ), "image decoder" );
679 if( p_owner == NULL )
680 return NULL;
681 p_dec = &p_owner->dec;
682 p_owner->p_image = p_image;
684 p_dec->p_module = NULL;
685 es_format_InitFromVideo( &p_dec->fmt_in, fmt );
686 es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
687 p_dec->b_frame_drop_allowed = false;
689 static const struct decoder_owner_callbacks dec_cbs =
691 .video = {
692 video_update_format,
693 video_new_buffer,
694 ImageQueueVideo,
697 p_dec->cbs = &dec_cbs;
699 /* Find a suitable decoder module */
700 p_dec->p_module = module_need_var( p_dec, "video decoder", "codec" );
701 if( !p_dec->p_module )
703 msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
704 "VLC probably does not support this image format.",
705 (char*)&p_dec->fmt_in.i_codec );
707 DeleteDecoder( p_dec );
708 return NULL;
711 return p_dec;
714 static void DeleteDecoder( decoder_t * p_dec )
716 if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
718 es_format_Clean( &p_dec->fmt_in );
719 es_format_Clean( &p_dec->fmt_out );
721 if( p_dec->p_description )
722 vlc_meta_Delete( p_dec->p_description );
724 vlc_object_release( p_dec );
725 p_dec = NULL;
728 static encoder_t *CreateEncoder( vlc_object_t *p_this, const video_format_t *fmt_in,
729 const video_format_t *fmt_out )
731 encoder_t *p_enc;
733 p_enc = sout_EncoderCreate( p_this );
734 if( p_enc == NULL )
735 return NULL;
737 p_enc->p_module = NULL;
738 es_format_InitFromVideo( &p_enc->fmt_in, fmt_in );
740 if( p_enc->fmt_in.video.i_visible_width == 0 ||
741 p_enc->fmt_in.video.i_visible_height == 0 ||
742 p_enc->fmt_out.video.i_visible_width == 0 ||
743 p_enc->fmt_out.video.i_visible_height == 0 )
745 if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
747 p_enc->fmt_in.video.i_width = fmt_out->i_width;
748 p_enc->fmt_in.video.i_height = fmt_out->i_height;
750 if( fmt_out->i_visible_width > 0 &&
751 fmt_out->i_visible_height > 0 )
753 p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
754 p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
756 else
758 p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
759 p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
762 } else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
763 fmt_out->i_sar_num * fmt_in->i_sar_den !=
764 fmt_out->i_sar_den * fmt_in->i_sar_num )
766 p_enc->fmt_in.video.i_width =
767 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
768 fmt_in->i_sar_den / fmt_out->i_sar_num;
769 p_enc->fmt_in.video.i_visible_width =
770 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
771 fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
774 p_enc->fmt_in.video.i_frame_rate = 25;
775 p_enc->fmt_in.video.i_frame_rate_base = 1;
777 es_format_InitFromVideo( &p_enc->fmt_out, fmt_out );
778 p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
779 p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
781 /* Find a suitable decoder module */
782 p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
783 if( !p_enc->p_module )
785 msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
786 "VLC probably does not support this image format.",
787 (char*)&p_enc->fmt_out.i_codec );
789 DeleteEncoder( p_enc );
790 return NULL;
792 p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
794 return p_enc;
797 static void DeleteEncoder( encoder_t * p_enc )
799 if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
801 es_format_Clean( &p_enc->fmt_in );
802 es_format_Clean( &p_enc->fmt_out );
804 vlc_object_release( p_enc );
805 p_enc = NULL;
808 static picture_t *filter_new_picture( filter_t *p_filter )
810 return picture_NewFromFormat( &p_filter->fmt_out.video );
813 static const struct filter_video_callbacks image_filter_cbs =
815 .buffer_new = filter_new_picture,
818 static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in,
819 const video_format_t *p_fmt_out )
821 filter_t *p_filter;
823 p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" );
824 p_filter->owner.video = &image_filter_cbs;
826 es_format_Copy( &p_filter->fmt_in, p_fmt_in );
827 es_format_Copy( &p_filter->fmt_out, p_fmt_in );
828 video_format_Copy( &p_filter->fmt_out.video, p_fmt_out );
830 /* whatever the input offset, write at offset 0 in the target image */
831 p_filter->fmt_out.video.i_x_offset = 0;
832 p_filter->fmt_out.video.i_y_offset = 0;
834 p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
835 p_filter->p_module = module_need( p_filter, "video converter", NULL, false );
837 if( !p_filter->p_module )
839 msg_Dbg( p_filter, "no video converter found" );
840 DeleteFilter( p_filter );
841 return NULL;
844 return p_filter;
847 static void DeleteFilter( filter_t * p_filter )
849 if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
851 es_format_Clean( &p_filter->fmt_in );
852 es_format_Clean( &p_filter->fmt_out );
854 vlc_object_release( p_filter );