1 /*****************************************************************************
2 * image.c : wrapper for image reading/writing facilities
3 *****************************************************************************
4 * Copyright (C) 2004-2007 VLC authors and VideoLAN
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 *****************************************************************************/
26 * This file contains the functions to handle the image_handler_t type
29 /*****************************************************************************
31 *****************************************************************************/
40 #include <vlc_common.h>
41 #include <vlc_codec.h>
43 #include <vlc_filter.h>
45 #include <vlc_image.h>
46 #include <vlc_stream.h>
50 #include <vlc_modules.h>
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
*, const uint8_t *, size_t,
66 static picture_t
*ImageReadUrl( image_handler_t
*, const char *,
67 const video_format_t
*, video_format_t
* );
68 static block_t
*ImageWrite( image_handler_t
*, picture_t
*,
69 const video_format_t
*, const video_format_t
* );
70 static int ImageWriteUrl( image_handler_t
*, picture_t
*,
71 const video_format_t
*, video_format_t
*, const char * );
73 static picture_t
*ImageConvert( image_handler_t
*, picture_t
*,
74 const video_format_t
*, video_format_t
* );
76 static decoder_t
*CreateDecoder( image_handler_t
*, const video_format_t
*,
77 const uint8_t *, size_t );
78 static void DeleteDecoder( decoder_t
* );
79 static encoder_t
*CreateEncoder( vlc_object_t
*, const video_format_t
*,
80 const video_format_t
* );
81 static void DeleteEncoder( encoder_t
* );
82 static filter_t
*CreateFilter( vlc_object_t
*, const es_format_t
*,
83 const video_format_t
* );
84 static void DeleteFilter( filter_t
* );
86 vlc_fourcc_t
image_Type2Fourcc( const char * );
87 vlc_fourcc_t
image_Ext2Fourcc( const char * );
88 /*static const char *Fourcc2Ext( vlc_fourcc_t );*/
90 #undef image_HandlerCreate
92 * Create an image_handler_t instance
95 image_handler_t
*image_HandlerCreate( vlc_object_t
*p_this
)
97 image_handler_t
*p_image
= calloc( 1, sizeof(image_handler_t
) );
101 p_image
->p_parent
= p_this
;
103 p_image
->pf_read
= ImageRead
;
104 p_image
->pf_read_url
= ImageReadUrl
;
105 p_image
->pf_write
= ImageWrite
;
106 p_image
->pf_write_url
= ImageWriteUrl
;
107 p_image
->pf_convert
= ImageConvert
;
109 p_image
->outfifo
= picture_fifo_New();
115 * Delete the image_handler_t instance
118 void image_HandlerDelete( image_handler_t
*p_image
)
120 if( !p_image
) return;
122 if( p_image
->p_dec
) DeleteDecoder( p_image
->p_dec
);
123 if( p_image
->p_enc
) DeleteEncoder( p_image
->p_enc
);
124 if( p_image
->p_filter
) DeleteFilter( p_image
->p_filter
);
126 picture_fifo_Delete( p_image
->outfifo
);
137 static void ImageQueueVideo( decoder_t
*p_dec
, picture_t
*p_pic
)
139 struct decoder_owner
*p_owner
= dec_get_owner( p_dec
);
140 picture_fifo_Push( p_owner
->p_image
->outfifo
, p_pic
);
143 static picture_t
*ImageRead( image_handler_t
*p_image
, block_t
*p_block
,
144 const video_format_t
*p_fmt_in
,
145 const uint8_t *p_extra
, size_t i_extra
,
146 video_format_t
*p_fmt_out
)
148 picture_t
*p_pic
= NULL
;
150 /* Check if we can reuse the current decoder */
151 if( p_image
->p_dec
&&
152 p_image
->p_dec
->fmt_in
.i_codec
!= p_fmt_in
->i_chroma
)
154 DeleteDecoder( p_image
->p_dec
);
158 /* Start a decoder */
159 if( !p_image
->p_dec
)
161 p_image
->p_dec
= CreateDecoder( p_image
, p_fmt_in
,
163 if( !p_image
->p_dec
)
165 block_Release(p_block
);
168 if( p_image
->p_dec
->fmt_out
.i_cat
!= VIDEO_ES
)
170 DeleteDecoder( p_image
->p_dec
);
171 p_image
->p_dec
= NULL
;
172 block_Release(p_block
);
177 p_block
->i_pts
= p_block
->i_dts
= vlc_tick_now();
178 int ret
= p_image
->p_dec
->pf_decode( p_image
->p_dec
, p_block
);
179 if( ret
== VLCDEC_SUCCESS
)
182 p_image
->p_dec
->pf_decode( p_image
->p_dec
, NULL
);
184 p_pic
= picture_fifo_Pop( p_image
->outfifo
);
186 unsigned lostcount
= 0;
188 while( ( lostpic
= picture_fifo_Pop( p_image
->outfifo
) ) != NULL
)
190 picture_Release( lostpic
);
194 msg_Warn( p_image
->p_parent
, "Image decoder output more than one "
195 "picture (%u)", lostcount
);
200 msg_Warn( p_image
->p_parent
, "no image decoded" );
204 if( !p_fmt_out
->i_chroma
)
205 p_fmt_out
->i_chroma
= p_image
->p_dec
->fmt_out
.video
.i_chroma
;
206 if( !p_fmt_out
->i_width
&& p_fmt_out
->i_height
)
207 p_fmt_out
->i_width
= (int64_t)p_image
->p_dec
->fmt_out
.video
.i_width
*
208 p_image
->p_dec
->fmt_out
.video
.i_sar_num
*
209 p_fmt_out
->i_height
/
210 p_image
->p_dec
->fmt_out
.video
.i_height
/
211 p_image
->p_dec
->fmt_out
.video
.i_sar_den
;
213 if( !p_fmt_out
->i_height
&& p_fmt_out
->i_width
)
214 p_fmt_out
->i_height
= (int64_t)p_image
->p_dec
->fmt_out
.video
.i_height
*
215 p_image
->p_dec
->fmt_out
.video
.i_sar_den
*
217 p_image
->p_dec
->fmt_out
.video
.i_width
/
218 p_image
->p_dec
->fmt_out
.video
.i_sar_num
;
219 if( !p_fmt_out
->i_width
)
220 p_fmt_out
->i_width
= p_image
->p_dec
->fmt_out
.video
.i_width
;
221 if( !p_fmt_out
->i_height
)
222 p_fmt_out
->i_height
= p_image
->p_dec
->fmt_out
.video
.i_height
;
223 if( !p_fmt_out
->i_visible_width
)
224 p_fmt_out
->i_visible_width
= p_fmt_out
->i_width
;
225 if( !p_fmt_out
->i_visible_height
)
226 p_fmt_out
->i_visible_height
= p_fmt_out
->i_height
;
228 /* Check if we need chroma conversion or resizing */
229 if( p_image
->p_dec
->fmt_out
.video
.i_chroma
!= p_fmt_out
->i_chroma
||
230 p_image
->p_dec
->fmt_out
.video
.i_width
!= p_fmt_out
->i_width
||
231 p_image
->p_dec
->fmt_out
.video
.i_height
!= p_fmt_out
->i_height
)
233 if( p_image
->p_filter
)
234 if( p_image
->p_filter
->fmt_in
.video
.i_chroma
!=
235 p_image
->p_dec
->fmt_out
.video
.i_chroma
||
236 p_image
->p_filter
->fmt_out
.video
.i_chroma
!= p_fmt_out
->i_chroma
)
238 /* We need to restart a new filter */
239 DeleteFilter( p_image
->p_filter
);
240 p_image
->p_filter
= 0;
244 if( !p_image
->p_filter
)
247 CreateFilter( p_image
->p_parent
, &p_image
->p_dec
->fmt_out
,
250 if( !p_image
->p_filter
)
252 picture_Release( p_pic
);
258 /* Filters should handle on-the-fly size changes */
259 p_image
->p_filter
->fmt_in
= p_image
->p_dec
->fmt_out
;
260 p_image
->p_filter
->fmt_out
= p_image
->p_dec
->fmt_out
;
261 p_image
->p_filter
->fmt_out
.i_codec
= p_fmt_out
->i_chroma
;
262 p_image
->p_filter
->fmt_out
.video
= *p_fmt_out
;
265 p_pic
= p_image
->p_filter
->pf_video_filter( p_image
->p_filter
, p_pic
);
267 video_format_Clean( p_fmt_out
);
268 video_format_Copy( p_fmt_out
, &p_image
->p_filter
->fmt_out
.video
);
272 video_format_Clean( p_fmt_out
);
273 video_format_Copy( p_fmt_out
, &p_image
->p_dec
->fmt_out
.video
);
279 static picture_t
*ImageReadUrl( image_handler_t
*p_image
, const char *psz_url
,
280 const video_format_t
*p_fmt_in
,
281 video_format_t
*p_fmt_out
)
285 stream_t
*p_stream
= NULL
;
288 p_stream
= vlc_stream_NewURL( p_image
->p_parent
, psz_url
);
292 msg_Dbg( p_image
->p_parent
, "could not open %s for reading",
297 if( vlc_stream_GetSize( p_stream
, &i_size
) || i_size
> SSIZE_MAX
)
299 msg_Dbg( p_image
->p_parent
, "could not read %s", psz_url
);
303 p_block
= vlc_stream_Block( p_stream
, i_size
);
304 if( p_block
== NULL
)
307 video_format_t fmtin
;
308 video_format_Init( &fmtin
, p_fmt_in
->i_chroma
);
309 video_format_Copy( &fmtin
, p_fmt_in
);
311 if( !fmtin
.i_chroma
)
313 char *psz_mime
= stream_MimeType( p_stream
);
314 if( psz_mime
!= NULL
)
316 fmtin
.i_chroma
= image_Mime2Fourcc( psz_mime
);
319 if( !fmtin
.i_chroma
)
321 /* Try to guess format from file name */
322 fmtin
.i_chroma
= image_Ext2Fourcc( psz_url
);
325 vlc_stream_Delete( p_stream
);
328 p_pic
= ImageRead( p_image
, p_block
, &fmtin
, NULL
, 0, p_fmt_out
);
330 video_format_Clean( &fmtin
);
334 vlc_stream_Delete( p_stream
);
338 /* FIXME: refactor by splitting video_format_IsSimilar() API */
339 static bool BitMapFormatIsSimilar( const video_format_t
*f1
,
340 const video_format_t
*f2
)
342 if( f1
->i_chroma
== VLC_CODEC_RGB15
||
343 f1
->i_chroma
== VLC_CODEC_RGB16
||
344 f1
->i_chroma
== VLC_CODEC_RGB24
||
345 f1
->i_chroma
== VLC_CODEC_RGB32
)
347 video_format_t v1
= *f1
;
348 video_format_t v2
= *f2
;
350 video_format_FixRgb( &v1
);
351 video_format_FixRgb( &v2
);
353 if( v1
.i_rmask
!= v2
.i_rmask
||
354 v1
.i_gmask
!= v2
.i_gmask
||
355 v1
.i_bmask
!= v2
.i_bmask
)
366 static block_t
*ImageWrite( image_handler_t
*p_image
, picture_t
*p_pic
,
367 const video_format_t
*p_fmt_in
,
368 const video_format_t
*p_fmt_out
)
372 /* Check if we can reuse the current encoder */
373 if( p_image
->p_enc
&&
374 ( p_image
->p_enc
->fmt_out
.i_codec
!= p_fmt_out
->i_chroma
||
375 p_image
->p_enc
->fmt_out
.video
.i_width
!= p_fmt_out
->i_width
||
376 p_image
->p_enc
->fmt_out
.video
.i_height
!= p_fmt_out
->i_height
) )
378 DeleteEncoder( p_image
->p_enc
);
382 /* Start an encoder */
383 if( !p_image
->p_enc
)
385 p_image
->p_enc
= CreateEncoder( p_image
->p_parent
,
386 p_fmt_in
, p_fmt_out
);
387 if( !p_image
->p_enc
) return NULL
;
390 /* Check if we need chroma conversion or resizing */
391 if( p_image
->p_enc
->fmt_in
.video
.i_chroma
!= p_fmt_in
->i_chroma
||
392 p_image
->p_enc
->fmt_in
.video
.i_width
!= p_fmt_in
->i_width
||
393 p_image
->p_enc
->fmt_in
.video
.i_height
!= p_fmt_in
->i_height
||
394 !BitMapFormatIsSimilar( &p_image
->p_enc
->fmt_in
.video
, p_fmt_in
) )
396 picture_t
*p_tmp_pic
;
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
!=
401 p_image
->p_enc
->fmt_in
.video
.i_chroma
||
402 !BitMapFormatIsSimilar( &p_image
->p_filter
->fmt_in
.video
, p_fmt_in
) )
404 /* We need to restart a new filter */
405 DeleteFilter( p_image
->p_filter
);
406 p_image
->p_filter
= 0;
410 if( !p_image
->p_filter
)
413 es_format_Init( &fmt_in
, VIDEO_ES
, p_fmt_in
->i_chroma
);
414 fmt_in
.video
= *p_fmt_in
;
417 CreateFilter( p_image
->p_parent
, &fmt_in
,
418 &p_image
->p_enc
->fmt_in
.video
);
420 if( !p_image
->p_filter
)
427 /* Filters should handle on-the-fly size changes */
428 p_image
->p_filter
->fmt_in
.i_codec
= p_fmt_in
->i_chroma
;
429 p_image
->p_filter
->fmt_out
.video
= *p_fmt_in
;
430 p_image
->p_filter
->fmt_out
.i_codec
=p_image
->p_enc
->fmt_in
.i_codec
;
431 p_image
->p_filter
->fmt_out
.video
= p_image
->p_enc
->fmt_in
.video
;
434 picture_Hold( p_pic
);
437 p_image
->p_filter
->pf_video_filter( p_image
->p_filter
, p_pic
);
439 if( likely(p_tmp_pic
!= NULL
) )
441 p_block
= p_image
->p_enc
->pf_encode_video( p_image
->p_enc
,
443 picture_Release( p_tmp_pic
);
450 p_block
= p_image
->p_enc
->pf_encode_video( p_image
->p_enc
, p_pic
);
455 msg_Dbg( p_image
->p_parent
, "no image encoded" );
462 static int ImageWriteUrl( image_handler_t
*p_image
, picture_t
*p_pic
,
463 const video_format_t
*p_fmt_in
, video_format_t
*p_fmt_out
,
464 const char *psz_url
)
469 if( !p_fmt_out
->i_chroma
)
471 /* Try to guess format from file name */
472 p_fmt_out
->i_chroma
= image_Ext2Fourcc( psz_url
);
475 file
= vlc_fopen( psz_url
, "wb" );
478 msg_Err( p_image
->p_parent
, "%s: %s", psz_url
, vlc_strerror_c(errno
) );
482 p_block
= ImageWrite( p_image
, p_pic
, p_fmt_in
, p_fmt_out
);
487 if( fwrite( p_block
->p_buffer
, p_block
->i_buffer
, 1, file
) != 1 )
489 block_Release( p_block
);
492 if( fclose( file
) && !err
)
498 msg_Err( p_image
->p_parent
, "%s: %s", psz_url
, vlc_strerror_c(errno
) );
501 return err
? VLC_EGENERIC
: VLC_SUCCESS
;
505 * Convert an image to a different format
509 static picture_t
*ImageConvert( image_handler_t
*p_image
, picture_t
*p_pic
,
510 const video_format_t
*p_fmt_in
,
511 video_format_t
*p_fmt_out
)
515 if( !p_fmt_out
->i_width
&& !p_fmt_out
->i_height
&&
516 p_fmt_out
->i_sar_num
&& p_fmt_out
->i_sar_den
&&
517 p_fmt_out
->i_sar_num
* p_fmt_in
->i_sar_den
!=
518 p_fmt_out
->i_sar_den
* p_fmt_in
->i_sar_num
)
521 p_fmt_in
->i_sar_num
* (int64_t)p_fmt_out
->i_sar_den
*
522 p_fmt_in
->i_width
/ p_fmt_in
->i_sar_den
/ p_fmt_out
->i_sar_num
;
523 p_fmt_out
->i_visible_width
=
524 p_fmt_in
->i_sar_num
* (int64_t)p_fmt_out
->i_sar_den
*
525 p_fmt_in
->i_visible_width
/ p_fmt_in
->i_sar_den
/
526 p_fmt_out
->i_sar_num
;
529 if( !p_fmt_out
->i_chroma
) p_fmt_out
->i_chroma
= p_fmt_in
->i_chroma
;
530 if( !p_fmt_out
->i_width
)
531 p_fmt_out
->i_width
= p_fmt_out
->i_visible_width
= p_fmt_in
->i_width
;
532 if( !p_fmt_out
->i_height
)
533 p_fmt_out
->i_height
= p_fmt_out
->i_visible_height
= p_fmt_in
->i_height
;
534 if( !p_fmt_out
->i_sar_num
) p_fmt_out
->i_sar_num
= p_fmt_in
->i_sar_num
;
535 if( !p_fmt_out
->i_sar_den
) p_fmt_out
->i_sar_den
= p_fmt_in
->i_sar_den
;
537 if( p_image
->p_filter
)
538 if( p_image
->p_filter
->fmt_in
.video
.i_chroma
!= p_fmt_in
->i_chroma
||
539 p_image
->p_filter
->fmt_out
.video
.i_chroma
!= p_fmt_out
->i_chroma
)
541 /* We need to restart a new filter */
542 DeleteFilter( p_image
->p_filter
);
543 p_image
->p_filter
= NULL
;
547 if( !p_image
->p_filter
)
550 es_format_Init( &fmt_in
, VIDEO_ES
, p_fmt_in
->i_chroma
);
551 fmt_in
.video
= *p_fmt_in
;
554 CreateFilter( p_image
->p_parent
, &fmt_in
, p_fmt_out
);
556 if( !p_image
->p_filter
)
563 /* Filters should handle on-the-fly size changes */
564 p_image
->p_filter
->fmt_in
.video
= *p_fmt_in
;
565 p_image
->p_filter
->fmt_out
.video
= *p_fmt_out
;
568 picture_Hold( p_pic
);
570 p_pif
= p_image
->p_filter
->pf_video_filter( p_image
->p_filter
, p_pic
);
572 if( p_fmt_in
->i_chroma
== p_fmt_out
->i_chroma
&&
573 p_fmt_in
->i_width
== p_fmt_out
->i_width
&&
574 p_fmt_in
->i_height
== p_fmt_out
->i_height
)
576 /* Duplicate image */
577 picture_Release( p_pif
); /* XXX: Better fix must be possible */
578 p_pif
= filter_NewPicture( p_image
->p_filter
);
580 picture_Copy( p_pif
, p_pic
);
592 vlc_fourcc_t i_codec
;
593 const char psz_ext
[7];
597 { VLC_CODEC_JPEG
, "jpeg" },
598 { VLC_CODEC_JPEG
, "jpg" },
599 { VLC_CODEC_JPEGLS
, "ljpg" },
600 { VLC_CODEC_BPG
, "bpg" },
601 { VLC_CODEC_PNG
, "png" },
602 { VLC_CODEC_PGM
, "pgm" },
603 { VLC_CODEC_PGMYUV
, "pgmyuv" },
604 { VLC_FOURCC('p','b','m',' '), "pbm" },
605 { VLC_FOURCC('p','a','m',' '), "pam" },
606 { VLC_CODEC_TARGA
, "tga" },
607 { VLC_CODEC_BMP
, "bmp" },
608 { VLC_CODEC_PNM
, "pnm" },
609 { VLC_FOURCC('x','p','m',' '), "xpm" },
610 { VLC_FOURCC('x','c','f',' '), "xcf" },
611 { VLC_CODEC_PCX
, "pcx" },
612 { VLC_CODEC_GIF
, "gif" },
613 { VLC_CODEC_SVG
, "svg" },
614 { VLC_CODEC_TIFF
, "tif" },
615 { VLC_CODEC_TIFF
, "tiff" },
616 { VLC_FOURCC('l','b','m',' '), "lbm" },
617 { VLC_CODEC_PPM
, "ppm" },
620 vlc_fourcc_t
image_Type2Fourcc( const char *psz_type
)
622 for( unsigned i
= 0; i
< ARRAY_SIZE(ext_table
); i
++ )
623 if( !strcasecmp( ext_table
[i
].psz_ext
, psz_type
) )
624 return ext_table
[i
].i_codec
;
629 vlc_fourcc_t
image_Ext2Fourcc( const char *psz_name
)
631 psz_name
= strrchr( psz_name
, '.' );
632 if( !psz_name
) return 0;
635 return image_Type2Fourcc( psz_name
);
640 vlc_fourcc_t i_codec
;
641 const char *psz_mime
;
644 { VLC_CODEC_BMP
, "image/bmp" },
645 { VLC_CODEC_BMP
, "image/x-bmp" },
646 { VLC_CODEC_BMP
, "image/x-bitmap" },
647 { VLC_CODEC_BMP
, "image/x-ms-bmp" },
648 { VLC_CODEC_PNM
, "image/x-portable-anymap" },
649 { VLC_CODEC_PNM
, "image/x-portable-bitmap" },
650 { VLC_CODEC_PNM
, "image/x-portable-graymap" },
651 { VLC_CODEC_PNM
, "image/x-portable-pixmap" },
652 { VLC_CODEC_GIF
, "image/gif" },
653 { VLC_CODEC_JPEG
, "image/jpeg" },
654 { VLC_CODEC_BPG
, "image/bpg" },
655 { VLC_CODEC_PCX
, "image/pcx" },
656 { VLC_CODEC_PNG
, "image/png" },
657 { VLC_CODEC_SVG
, "image/svg+xml" },
658 { VLC_CODEC_TIFF
, "image/tiff" },
659 { VLC_CODEC_TARGA
, "image/x-tga" },
660 { VLC_FOURCC('x','p','m',' '), "image/x-xpixmap" },
664 vlc_fourcc_t
image_Mime2Fourcc( const char *psz_mime
)
666 for( int i
= 0; mime_table
[i
].i_codec
; i
++ )
667 if( !strcmp( psz_mime
, mime_table
[i
].psz_mime
) )
668 return mime_table
[i
].i_codec
;
672 static int video_update_format( decoder_t
*p_dec
)
674 p_dec
->fmt_out
.video
.i_chroma
= p_dec
->fmt_out
.i_codec
;
678 static picture_t
*video_new_buffer( decoder_t
*p_dec
)
680 return picture_NewFromFormat( &p_dec
->fmt_out
.video
);
683 static decoder_t
*CreateDecoder( image_handler_t
*p_image
, const video_format_t
*fmt
,
684 const uint8_t *p_extra
, size_t i_extra
)
687 struct decoder_owner
*p_owner
;
689 p_owner
= vlc_custom_create( p_image
->p_parent
, sizeof( *p_owner
), "image decoder" );
690 if( p_owner
== NULL
)
692 p_dec
= &p_owner
->dec
;
693 p_owner
->p_image
= p_image
;
695 p_dec
->p_module
= NULL
;
696 es_format_InitFromVideo( &p_dec
->fmt_in
, fmt
);
699 p_dec
->fmt_in
.p_extra
= malloc( i_extra
);
700 if( p_dec
->fmt_in
.p_extra
)
702 memcpy( p_dec
->fmt_in
.p_extra
, p_extra
, i_extra
);
703 p_dec
->fmt_in
.i_extra
= i_extra
;
706 es_format_Init( &p_dec
->fmt_out
, VIDEO_ES
, 0 );
707 p_dec
->b_frame_drop_allowed
= false;
709 static const struct decoder_owner_callbacks dec_cbs
=
712 .format_update
= video_update_format
,
713 .buffer_new
= video_new_buffer
,
714 .queue
= ImageQueueVideo
,
717 p_dec
->cbs
= &dec_cbs
;
719 /* Find a suitable decoder module */
720 p_dec
->p_module
= module_need_var( p_dec
, "video decoder", "codec" );
721 if( !p_dec
->p_module
)
723 msg_Err( p_dec
, "no suitable decoder module for fourcc `%4.4s'. "
724 "VLC probably does not support this image format.",
725 (char*)&p_dec
->fmt_in
.i_codec
);
727 DeleteDecoder( p_dec
);
734 static void DeleteDecoder( decoder_t
* p_dec
)
736 if( p_dec
->p_module
) module_unneed( p_dec
, p_dec
->p_module
);
738 es_format_Clean( &p_dec
->fmt_in
);
739 es_format_Clean( &p_dec
->fmt_out
);
741 if( p_dec
->p_description
)
742 vlc_meta_Delete( p_dec
->p_description
);
744 vlc_object_release( p_dec
);
748 static encoder_t
*CreateEncoder( vlc_object_t
*p_this
, const video_format_t
*fmt_in
,
749 const video_format_t
*fmt_out
)
753 p_enc
= sout_EncoderCreate( p_this
);
757 p_enc
->p_module
= NULL
;
758 es_format_InitFromVideo( &p_enc
->fmt_in
, fmt_in
);
760 if( p_enc
->fmt_in
.video
.i_visible_width
== 0 ||
761 p_enc
->fmt_in
.video
.i_visible_height
== 0 ||
762 p_enc
->fmt_out
.video
.i_visible_width
== 0 ||
763 p_enc
->fmt_out
.video
.i_visible_height
== 0 )
765 if( fmt_out
->i_width
> 0 && fmt_out
->i_height
> 0 )
767 p_enc
->fmt_in
.video
.i_width
= fmt_out
->i_width
;
768 p_enc
->fmt_in
.video
.i_height
= fmt_out
->i_height
;
770 if( fmt_out
->i_visible_width
> 0 &&
771 fmt_out
->i_visible_height
> 0 )
773 p_enc
->fmt_in
.video
.i_visible_width
= fmt_out
->i_visible_width
;
774 p_enc
->fmt_in
.video
.i_visible_height
= fmt_out
->i_visible_height
;
778 p_enc
->fmt_in
.video
.i_visible_width
= fmt_out
->i_width
;
779 p_enc
->fmt_in
.video
.i_visible_height
= fmt_out
->i_height
;
782 } else if( fmt_out
->i_sar_num
&& fmt_out
->i_sar_den
&&
783 fmt_out
->i_sar_num
* fmt_in
->i_sar_den
!=
784 fmt_out
->i_sar_den
* fmt_in
->i_sar_num
)
786 p_enc
->fmt_in
.video
.i_width
=
787 fmt_in
->i_sar_num
* (int64_t)fmt_out
->i_sar_den
* fmt_in
->i_width
/
788 fmt_in
->i_sar_den
/ fmt_out
->i_sar_num
;
789 p_enc
->fmt_in
.video
.i_visible_width
=
790 fmt_in
->i_sar_num
* (int64_t)fmt_out
->i_sar_den
*
791 fmt_in
->i_visible_width
/ fmt_in
->i_sar_den
/ fmt_out
->i_sar_num
;
794 p_enc
->fmt_in
.video
.i_frame_rate
= 25;
795 p_enc
->fmt_in
.video
.i_frame_rate_base
= 1;
797 es_format_InitFromVideo( &p_enc
->fmt_out
, fmt_out
);
798 p_enc
->fmt_out
.video
.i_width
= p_enc
->fmt_in
.video
.i_width
;
799 p_enc
->fmt_out
.video
.i_height
= p_enc
->fmt_in
.video
.i_height
;
801 /* Find a suitable decoder module */
802 p_enc
->p_module
= module_need( p_enc
, "encoder", NULL
, false );
803 if( !p_enc
->p_module
)
805 msg_Err( p_enc
, "no suitable encoder module for fourcc `%4.4s'.\n"
806 "VLC probably does not support this image format.",
807 (char*)&p_enc
->fmt_out
.i_codec
);
809 DeleteEncoder( p_enc
);
812 p_enc
->fmt_in
.video
.i_chroma
= p_enc
->fmt_in
.i_codec
;
817 static void DeleteEncoder( encoder_t
* p_enc
)
819 if( p_enc
->p_module
) module_unneed( p_enc
, p_enc
->p_module
);
821 es_format_Clean( &p_enc
->fmt_in
);
822 es_format_Clean( &p_enc
->fmt_out
);
824 vlc_object_release( p_enc
);
828 static picture_t
*filter_new_picture( filter_t
*p_filter
)
830 return picture_NewFromFormat( &p_filter
->fmt_out
.video
);
833 static const struct filter_video_callbacks image_filter_cbs
=
835 .buffer_new
= filter_new_picture
,
838 static filter_t
*CreateFilter( vlc_object_t
*p_this
, const es_format_t
*p_fmt_in
,
839 const video_format_t
*p_fmt_out
)
843 p_filter
= vlc_custom_create( p_this
, sizeof(filter_t
), "filter" );
844 p_filter
->owner
.video
= &image_filter_cbs
;
846 es_format_Copy( &p_filter
->fmt_in
, p_fmt_in
);
847 es_format_Copy( &p_filter
->fmt_out
, p_fmt_in
);
848 video_format_Copy( &p_filter
->fmt_out
.video
, p_fmt_out
);
850 /* whatever the input offset, write at offset 0 in the target image */
851 p_filter
->fmt_out
.video
.i_x_offset
= 0;
852 p_filter
->fmt_out
.video
.i_y_offset
= 0;
854 p_filter
->fmt_out
.i_codec
= p_fmt_out
->i_chroma
;
855 p_filter
->p_module
= module_need( p_filter
, "video converter", NULL
, false );
857 if( !p_filter
->p_module
)
859 msg_Dbg( p_filter
, "no video converter found" );
860 DeleteFilter( p_filter
);
867 static void DeleteFilter( filter_t
* p_filter
)
869 if( p_filter
->p_module
) module_unneed( p_filter
, p_filter
->p_module
);
871 es_format_Clean( &p_filter
->fmt_in
);
872 es_format_Clean( &p_filter
->fmt_out
);
874 vlc_object_release( p_filter
);