vout: merge vout_control.h with vout_internal.h
[vlc.git] / src / misc / image.c
blob395b9d39cb4010e463f69289c5964f9188563d59
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 static picture_t *ImageRead( image_handler_t *, block_t *,
53 const video_format_t *, video_format_t * );
54 static picture_t *ImageReadUrl( image_handler_t *, const char *,
55 video_format_t *, video_format_t * );
56 static block_t *ImageWrite( image_handler_t *, picture_t *,
57 const video_format_t *, const video_format_t * );
58 static int ImageWriteUrl( image_handler_t *, picture_t *,
59 const video_format_t *, video_format_t *, const char * );
61 static picture_t *ImageConvert( image_handler_t *, picture_t *,
62 const video_format_t *, video_format_t * );
64 static decoder_t *CreateDecoder( vlc_object_t *, const video_format_t * );
65 static void DeleteDecoder( decoder_t * );
66 static encoder_t *CreateEncoder( vlc_object_t *, const video_format_t *,
67 const video_format_t * );
68 static void DeleteEncoder( encoder_t * );
69 static filter_t *CreateFilter( vlc_object_t *, const es_format_t *,
70 const video_format_t * );
71 static void DeleteFilter( filter_t * );
73 vlc_fourcc_t image_Type2Fourcc( const char * );
74 vlc_fourcc_t image_Ext2Fourcc( const char * );
75 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
77 #undef image_HandlerCreate
78 /**
79 * Create an image_handler_t instance
82 image_handler_t *image_HandlerCreate( vlc_object_t *p_this )
84 image_handler_t *p_image = calloc( 1, sizeof(image_handler_t) );
85 if( !p_image )
86 return NULL;
88 p_image->p_parent = p_this;
90 p_image->pf_read = ImageRead;
91 p_image->pf_read_url = ImageReadUrl;
92 p_image->pf_write = ImageWrite;
93 p_image->pf_write_url = ImageWriteUrl;
94 p_image->pf_convert = ImageConvert;
96 p_image->outfifo = picture_fifo_New();
98 return p_image;
102 * Delete the image_handler_t instance
105 void image_HandlerDelete( image_handler_t *p_image )
107 if( !p_image ) return;
109 if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
110 if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
111 if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
113 picture_fifo_Delete( p_image->outfifo );
115 free( p_image );
116 p_image = NULL;
120 * Read an image
124 static int ImageQueueVideo( decoder_t *p_dec, picture_t *p_pic )
126 image_handler_t *p_image = p_dec->p_queue_ctx;
127 picture_fifo_Push( p_image->outfifo, p_pic );
128 return 0;
131 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
132 const video_format_t *p_fmt_in,
133 video_format_t *p_fmt_out )
135 picture_t *p_pic = NULL;
137 /* Check if we can reuse the current decoder */
138 if( p_image->p_dec &&
139 p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
141 DeleteDecoder( p_image->p_dec );
142 p_image->p_dec = 0;
145 /* Start a decoder */
146 if( !p_image->p_dec )
148 p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
149 if( !p_image->p_dec )
151 block_Release(p_block);
152 return NULL;
154 if( p_image->p_dec->fmt_out.i_cat != VIDEO_ES )
156 DeleteDecoder( p_image->p_dec );
157 p_image->p_dec = NULL;
158 block_Release(p_block);
159 return NULL;
161 p_image->p_dec->pf_queue_video = ImageQueueVideo;
162 p_image->p_dec->p_queue_ctx = p_image;
165 p_block->i_pts = p_block->i_dts = mdate();
166 int ret = p_image->p_dec->pf_decode( p_image->p_dec, p_block );
167 if( ret == VLCDEC_SUCCESS )
169 /* Drain */
170 p_image->p_dec->pf_decode( p_image->p_dec, NULL );
172 p_pic = picture_fifo_Pop( p_image->outfifo );
174 unsigned lostcount = 0;
175 picture_t *lostpic;
176 while( ( lostpic = picture_fifo_Pop( p_image->outfifo ) ) != NULL )
178 picture_Release( lostpic );
179 lostcount++;
181 if( lostcount > 0 )
182 msg_Warn( p_image->p_parent, "Image decoder output more than one "
183 "picture (%d)", lostcount );
186 if( p_pic == NULL )
188 msg_Warn( p_image->p_parent, "no image decoded" );
189 return 0;
192 if( !p_fmt_out->i_chroma )
193 p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
194 if( !p_fmt_out->i_width && p_fmt_out->i_height )
195 p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
196 p_image->p_dec->fmt_out.video.i_sar_num *
197 p_fmt_out->i_height /
198 p_image->p_dec->fmt_out.video.i_height /
199 p_image->p_dec->fmt_out.video.i_sar_den;
201 if( !p_fmt_out->i_height && p_fmt_out->i_width )
202 p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
203 p_image->p_dec->fmt_out.video.i_sar_den *
204 p_fmt_out->i_width /
205 p_image->p_dec->fmt_out.video.i_width /
206 p_image->p_dec->fmt_out.video.i_sar_num;
207 if( !p_fmt_out->i_width )
208 p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
209 if( !p_fmt_out->i_height )
210 p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
211 if( !p_fmt_out->i_visible_width )
212 p_fmt_out->i_visible_width = p_fmt_out->i_width;
213 if( !p_fmt_out->i_visible_height )
214 p_fmt_out->i_visible_height = p_fmt_out->i_height;
216 /* Check if we need chroma conversion or resizing */
217 if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
218 p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
219 p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
221 if( p_image->p_filter )
222 if( p_image->p_filter->fmt_in.video.i_chroma !=
223 p_image->p_dec->fmt_out.video.i_chroma ||
224 p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
226 /* We need to restart a new filter */
227 DeleteFilter( p_image->p_filter );
228 p_image->p_filter = 0;
231 /* Start a filter */
232 if( !p_image->p_filter )
234 p_image->p_filter =
235 CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
236 p_fmt_out );
238 if( !p_image->p_filter )
240 picture_Release( p_pic );
241 return NULL;
244 else
246 /* Filters should handle on-the-fly size changes */
247 p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
248 p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
249 p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
250 p_image->p_filter->fmt_out.video = *p_fmt_out;
253 p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
255 video_format_Clean( p_fmt_out );
256 video_format_Copy( p_fmt_out, &p_image->p_filter->fmt_out.video );
258 else
260 video_format_Clean( p_fmt_out );
261 video_format_Copy( p_fmt_out, &p_image->p_dec->fmt_out.video );
264 return p_pic;
267 static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
268 video_format_t *p_fmt_in,
269 video_format_t *p_fmt_out )
271 block_t *p_block;
272 picture_t *p_pic;
273 stream_t *p_stream = NULL;
274 uint64_t i_size;
276 p_stream = vlc_stream_NewURL( p_image->p_parent, psz_url );
278 if( !p_stream )
280 msg_Dbg( p_image->p_parent, "could not open %s for reading",
281 psz_url );
282 return NULL;
285 if( vlc_stream_GetSize( p_stream, &i_size ) || i_size > SSIZE_MAX )
287 msg_Dbg( p_image->p_parent, "could not read %s", psz_url );
288 goto error;
291 p_block = vlc_stream_Block( p_stream, i_size );
292 if( p_block == NULL )
293 goto error;
295 if( !p_fmt_in->i_chroma )
297 char *psz_mime = stream_MimeType( p_stream );
298 if( psz_mime != NULL )
300 p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
301 free( psz_mime );
304 vlc_stream_Delete( p_stream );
306 if( !p_fmt_in->i_chroma )
308 /* Try to guess format from file name */
309 p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
312 p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
314 return p_pic;
315 error:
316 vlc_stream_Delete( p_stream );
317 return NULL;
320 /* FIXME: refactor by splitting video_format_IsSimilar() API */
321 static bool BitMapFormatIsSimilar( const video_format_t *f1,
322 const video_format_t *f2 )
324 if( f1->i_chroma == VLC_CODEC_RGB15 ||
325 f1->i_chroma == VLC_CODEC_RGB16 ||
326 f1->i_chroma == VLC_CODEC_RGB24 ||
327 f1->i_chroma == VLC_CODEC_RGB32 )
329 video_format_t v1 = *f1;
330 video_format_t v2 = *f2;
332 video_format_FixRgb( &v1 );
333 video_format_FixRgb( &v2 );
335 if( v1.i_rmask != v2.i_rmask ||
336 v1.i_gmask != v2.i_gmask ||
337 v1.i_bmask != v2.i_bmask )
338 return false;
340 return true;
344 * Write an image
348 static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
349 const video_format_t *p_fmt_in,
350 const video_format_t *p_fmt_out )
352 block_t *p_block;
354 /* Check if we can reuse the current encoder */
355 if( p_image->p_enc &&
356 ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
357 p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
358 p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
360 DeleteEncoder( p_image->p_enc );
361 p_image->p_enc = 0;
364 /* Start an encoder */
365 if( !p_image->p_enc )
367 p_image->p_enc = CreateEncoder( p_image->p_parent,
368 p_fmt_in, p_fmt_out );
369 if( !p_image->p_enc ) return NULL;
372 /* Check if we need chroma conversion or resizing */
373 if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
374 p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
375 p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height ||
376 !BitMapFormatIsSimilar( &p_image->p_enc->fmt_in.video, p_fmt_in ) )
378 picture_t *p_tmp_pic;
380 if( p_image->p_filter )
381 if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
382 p_image->p_filter->fmt_out.video.i_chroma !=
383 p_image->p_enc->fmt_in.video.i_chroma ||
384 !BitMapFormatIsSimilar( &p_image->p_filter->fmt_in.video, p_fmt_in ) )
386 /* We need to restart a new filter */
387 DeleteFilter( p_image->p_filter );
388 p_image->p_filter = 0;
391 /* Start a filter */
392 if( !p_image->p_filter )
394 es_format_t fmt_in;
395 es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
396 fmt_in.video = *p_fmt_in;
398 p_image->p_filter =
399 CreateFilter( p_image->p_parent, &fmt_in,
400 &p_image->p_enc->fmt_in.video );
402 if( !p_image->p_filter )
404 return NULL;
407 else
409 /* Filters should handle on-the-fly size changes */
410 p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
411 p_image->p_filter->fmt_out.video = *p_fmt_in;
412 p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
413 p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
416 picture_Hold( p_pic );
418 p_tmp_pic =
419 p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
421 if( likely(p_tmp_pic != NULL) )
423 p_block = p_image->p_enc->pf_encode_video( p_image->p_enc,
424 p_tmp_pic );
425 picture_Release( p_tmp_pic );
427 else
428 p_block = NULL;
430 else
432 p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
435 if( !p_block )
437 msg_Dbg( p_image->p_parent, "no image encoded" );
438 return 0;
441 return p_block;
444 static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
445 const video_format_t *p_fmt_in, video_format_t *p_fmt_out,
446 const char *psz_url )
448 block_t *p_block;
449 FILE *file;
451 if( !p_fmt_out->i_chroma )
453 /* Try to guess format from file name */
454 p_fmt_out->i_chroma = image_Ext2Fourcc( psz_url );
457 file = vlc_fopen( psz_url, "wb" );
458 if( !file )
460 msg_Err( p_image->p_parent, "%s: %s", psz_url, vlc_strerror_c(errno) );
461 return VLC_EGENERIC;
464 p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
466 int err = 0;
467 if( p_block )
469 if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, file ) != 1 )
470 err = errno;
471 block_Release( p_block );
474 if( fclose( file ) && !err )
475 err = errno;
477 if( err )
479 errno = err;
480 msg_Err( p_image->p_parent, "%s: %s", psz_url, vlc_strerror_c(errno) );
483 return err ? VLC_EGENERIC : VLC_SUCCESS;
487 * Convert an image to a different format
491 static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
492 const video_format_t *p_fmt_in,
493 video_format_t *p_fmt_out )
495 picture_t *p_pif;
497 if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
498 p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
499 p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
500 p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
502 p_fmt_out->i_width =
503 p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
504 p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
505 p_fmt_out->i_visible_width =
506 p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
507 p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
508 p_fmt_out->i_sar_num;
511 if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
512 if( !p_fmt_out->i_width )
513 p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
514 if( !p_fmt_out->i_height )
515 p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
516 if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
517 if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
519 if( p_image->p_filter )
520 if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
521 p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
523 /* We need to restart a new filter */
524 DeleteFilter( p_image->p_filter );
525 p_image->p_filter = NULL;
528 /* Start a filter */
529 if( !p_image->p_filter )
531 es_format_t fmt_in;
532 es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
533 fmt_in.video = *p_fmt_in;
535 p_image->p_filter =
536 CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out );
538 if( !p_image->p_filter )
540 return NULL;
543 else
545 /* Filters should handle on-the-fly size changes */
546 p_image->p_filter->fmt_in.video = *p_fmt_in;
547 p_image->p_filter->fmt_out.video = *p_fmt_out;
550 picture_Hold( p_pic );
552 p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
554 if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
555 p_fmt_in->i_width == p_fmt_out->i_width &&
556 p_fmt_in->i_height == p_fmt_out->i_height )
558 /* Duplicate image */
559 picture_Release( p_pif ); /* XXX: Better fix must be possible */
560 p_pif = filter_NewPicture( p_image->p_filter );
561 if( p_pif )
562 picture_Copy( p_pif, p_pic );
565 return p_pif;
569 * Misc functions
572 static const struct
574 vlc_fourcc_t i_codec;
575 const char psz_ext[7];
577 } ext_table[] =
579 { VLC_CODEC_JPEG, "jpeg" },
580 { VLC_CODEC_JPEG, "jpg" },
581 { VLC_CODEC_JPEGLS, "ljpg" },
582 { VLC_CODEC_BPG, "bpg" },
583 { VLC_CODEC_PNG, "png" },
584 { VLC_CODEC_PGM, "pgm" },
585 { VLC_CODEC_PGMYUV, "pgmyuv" },
586 { VLC_FOURCC('p','b','m',' '), "pbm" },
587 { VLC_FOURCC('p','a','m',' '), "pam" },
588 { VLC_CODEC_TARGA, "tga" },
589 { VLC_CODEC_BMP, "bmp" },
590 { VLC_CODEC_PNM, "pnm" },
591 { VLC_FOURCC('x','p','m',' '), "xpm" },
592 { VLC_FOURCC('x','c','f',' '), "xcf" },
593 { VLC_CODEC_PCX, "pcx" },
594 { VLC_CODEC_GIF, "gif" },
595 { VLC_CODEC_SVG, "svg" },
596 { VLC_CODEC_TIFF, "tif" },
597 { VLC_CODEC_TIFF, "tiff" },
598 { VLC_FOURCC('l','b','m',' '), "lbm" },
599 { VLC_CODEC_PPM, "ppm" },
602 vlc_fourcc_t image_Type2Fourcc( const char *psz_type )
604 for( unsigned i = 0; i < ARRAY_SIZE(ext_table); i++ )
605 if( !strcasecmp( ext_table[i].psz_ext, psz_type ) )
606 return ext_table[i].i_codec;
608 return 0;
611 vlc_fourcc_t image_Ext2Fourcc( const char *psz_name )
613 psz_name = strrchr( psz_name, '.' );
614 if( !psz_name ) return 0;
615 psz_name++;
617 return image_Type2Fourcc( psz_name );
620 static const struct
622 vlc_fourcc_t i_codec;
623 const char *psz_mime;
624 } mime_table[] =
626 { VLC_CODEC_BMP, "image/bmp" },
627 { VLC_CODEC_BMP, "image/x-bmp" },
628 { VLC_CODEC_BMP, "image/x-bitmap" },
629 { VLC_CODEC_BMP, "image/x-ms-bmp" },
630 { VLC_CODEC_PNM, "image/x-portable-anymap" },
631 { VLC_CODEC_PNM, "image/x-portable-bitmap" },
632 { VLC_CODEC_PNM, "image/x-portable-graymap" },
633 { VLC_CODEC_PNM, "image/x-portable-pixmap" },
634 { VLC_CODEC_GIF, "image/gif" },
635 { VLC_CODEC_JPEG, "image/jpeg" },
636 { VLC_CODEC_BPG, "image/bpg" },
637 { VLC_CODEC_PCX, "image/pcx" },
638 { VLC_CODEC_PNG, "image/png" },
639 { VLC_CODEC_SVG, "image/svg+xml" },
640 { VLC_CODEC_TIFF, "image/tiff" },
641 { VLC_CODEC_TARGA, "image/x-tga" },
642 { VLC_FOURCC('x','p','m',' '), "image/x-xpixmap" },
643 { 0, NULL }
646 vlc_fourcc_t image_Mime2Fourcc( const char *psz_mime )
648 for( int i = 0; mime_table[i].i_codec; i++ )
649 if( !strcmp( psz_mime, mime_table[i].psz_mime ) )
650 return mime_table[i].i_codec;
651 return 0;
654 static int video_update_format( decoder_t *p_dec )
656 p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
657 return 0;
660 static picture_t *video_new_buffer( decoder_t *p_dec )
662 return picture_NewFromFormat( &p_dec->fmt_out.video );
665 static decoder_t *CreateDecoder( vlc_object_t *p_this, const video_format_t *fmt )
667 decoder_t *p_dec;
669 p_dec = vlc_custom_create( p_this, sizeof( *p_dec ), "image decoder" );
670 if( p_dec == NULL )
671 return NULL;
673 p_dec->p_module = NULL;
674 es_format_InitFromVideo( &p_dec->fmt_in, fmt );
675 es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
676 p_dec->b_frame_drop_allowed = false;
678 p_dec->pf_vout_format_update = video_update_format;
679 p_dec->pf_vout_buffer_new = video_new_buffer;
681 /* Find a suitable decoder module */
682 p_dec->p_module = module_need_var( p_dec, "video decoder", "codec" );
683 if( !p_dec->p_module )
685 msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
686 "VLC probably does not support this image format.",
687 (char*)&p_dec->fmt_in.i_codec );
689 DeleteDecoder( p_dec );
690 return NULL;
693 return p_dec;
696 static void DeleteDecoder( decoder_t * p_dec )
698 if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
700 es_format_Clean( &p_dec->fmt_in );
701 es_format_Clean( &p_dec->fmt_out );
703 if( p_dec->p_description )
704 vlc_meta_Delete( p_dec->p_description );
706 vlc_object_release( p_dec );
707 p_dec = NULL;
710 static encoder_t *CreateEncoder( vlc_object_t *p_this, const video_format_t *fmt_in,
711 const video_format_t *fmt_out )
713 encoder_t *p_enc;
715 p_enc = sout_EncoderCreate( p_this );
716 if( p_enc == NULL )
717 return NULL;
719 p_enc->p_module = NULL;
720 es_format_InitFromVideo( &p_enc->fmt_in, fmt_in );
722 if( p_enc->fmt_in.video.i_visible_width == 0 ||
723 p_enc->fmt_in.video.i_visible_height == 0 ||
724 p_enc->fmt_out.video.i_visible_width == 0 ||
725 p_enc->fmt_out.video.i_visible_height == 0 )
727 if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
729 p_enc->fmt_in.video.i_width = fmt_out->i_width;
730 p_enc->fmt_in.video.i_height = fmt_out->i_height;
732 if( fmt_out->i_visible_width > 0 &&
733 fmt_out->i_visible_height > 0 )
735 p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
736 p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
738 else
740 p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
741 p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
744 } else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
745 fmt_out->i_sar_num * fmt_in->i_sar_den !=
746 fmt_out->i_sar_den * fmt_in->i_sar_num )
748 p_enc->fmt_in.video.i_width =
749 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
750 fmt_in->i_sar_den / fmt_out->i_sar_num;
751 p_enc->fmt_in.video.i_visible_width =
752 fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
753 fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
756 p_enc->fmt_in.video.i_frame_rate = 25;
757 p_enc->fmt_in.video.i_frame_rate_base = 1;
759 es_format_InitFromVideo( &p_enc->fmt_out, fmt_out );
760 p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
761 p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
763 /* Find a suitable decoder module */
764 p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
765 if( !p_enc->p_module )
767 msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
768 "VLC probably does not support this image format.",
769 (char*)&p_enc->fmt_out.i_codec );
771 DeleteEncoder( p_enc );
772 return NULL;
774 p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
776 return p_enc;
779 static void DeleteEncoder( encoder_t * p_enc )
781 if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
783 es_format_Clean( &p_enc->fmt_in );
784 es_format_Clean( &p_enc->fmt_out );
786 vlc_object_release( p_enc );
787 p_enc = NULL;
790 static picture_t *filter_new_picture( filter_t *p_filter )
792 return picture_NewFromFormat( &p_filter->fmt_out.video );
795 static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in,
796 const video_format_t *p_fmt_out )
798 filter_t *p_filter;
800 p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" );
801 p_filter->owner.video.buffer_new = filter_new_picture;
803 es_format_Copy( &p_filter->fmt_in, p_fmt_in );
804 es_format_Copy( &p_filter->fmt_out, p_fmt_in );
805 video_format_Copy( &p_filter->fmt_out.video, p_fmt_out );
807 /* whatever the input offset, write at offset 0 in the target image */
808 p_filter->fmt_out.video.i_x_offset = 0;
809 p_filter->fmt_out.video.i_y_offset = 0;
811 p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
812 p_filter->p_module = module_need( p_filter, "video converter", NULL, false );
814 if( !p_filter->p_module )
816 msg_Dbg( p_filter, "no video converter found" );
817 DeleteFilter( p_filter );
818 return NULL;
821 return p_filter;
824 static void DeleteFilter( filter_t * p_filter )
826 if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
828 es_format_Clean( &p_filter->fmt_in );
829 es_format_Clean( &p_filter->fmt_out );
831 vlc_object_release( p_filter );