[vlc-devel] [PATCH] -- improving the art files user experience ....
brezhoneg1
brezhoneg1 at yahoo.fr
Tue Jan 29 02:41:18 CET 2013
Hi,
Please, find attached a patch for review. This is a first draft to
check if this is the right direction to go into.
It was tested and it is fully functional.
Regards
Erwan
Le 28/01/2013 21:37, Rémi Denis-Courmont a écrit :
> Le lundi 28 janvier 2013 17:26:35, brezhoneg1 a écrit :
>> So, I just duplicated fenrir's content-based detection code into vlc
>> core (src/misc/image.c) and __ALL__ art files would then be displayed
>> without any problem.
> Moving code from plugins into the core is not desirable. It bloats the LibVLC
> run-time. And obviously, duplicating code is not a very good idea either.
>
>> So, the question, is : Would it be ok to move this content-based
>> detection at the vlc core (src/misc/image.c) so that it can be used
>> throughout vlc whenever a still image needs to be read ? Or, any other
>> means to benefit from this detection ?
> IMHO, if some code needs to be moved, then the image code should be moved to
> the image plugin. The image handler interface is already modularized anyway.
>
-------------- next part --------------
>From f1f4cc41e0027f48ef40d5b1cd889924b1a437e5 Mon Sep 17 00:00:00 2001
From: Erwan Tulou <erwan10 at videolan.org>
Date: Tue, 29 Jan 2013 01:18:08 +0100
Subject: [PATCH] image: move the image module as a plugin and use
content-based image detection
This patch does the following :
- move the core image module as a plugin (modules/demux/image2.c)
- create a image_helper.h file from fenrir's content detection code
- use this content detection in the new image plugin
- adapt the image demux to also use this helper
---
include/vlc_image.h | 6 +-
modules/demux/Modules.am | 4 +-
modules/demux/image.c | 301 +-----------------
modules/demux/image2.c | 719 ++++++++++++++++++++++++++++++++++++++++++
modules/demux/image_helper.h | 334 ++++++++++++++++++++
src/misc/image.c | 657 +-------------------------------------
6 files changed, 1080 insertions(+), 941 deletions(-)
create mode 100644 modules/demux/image2.c
create mode 100644 modules/demux/image_helper.h
diff --git a/include/vlc_image.h b/include/vlc_image.h
index 52bce1f..aae8db3 100644
--- a/include/vlc_image.h
+++ b/include/vlc_image.h
@@ -37,6 +37,11 @@ extern "C" {
struct image_handler_t
{
+ VLC_COMMON_MEMBERS
+
+ /* Module properties */
+ module_t *p_module;
+
picture_t * (*pf_read) ( image_handler_t *, block_t *,
video_format_t *, video_format_t * );
picture_t * (*pf_read_url) ( image_handler_t *, const char *,
@@ -53,7 +58,6 @@ struct image_handler_t
video_format_t *, const char * );
/* Private properties */
- vlc_object_t *p_parent;
decoder_t *p_dec;
encoder_t *p_enc;
filter_t *p_filter;
diff --git a/modules/demux/Modules.am b/modules/demux/Modules.am
index 4a0817c..6ad5d79 100644
--- a/modules/demux/Modules.am
+++ b/modules/demux/Modules.am
@@ -29,7 +29,8 @@ SOURCES_smf = smf.c
SOURCES_gme = gme.c dummy.cpp
SOURCES_sid = sid.cpp
SOURCES_dirac = dirac.c
-SOURCES_image = image.c mxpeg_helper.h
+SOURCES_image = image.c image_helper.h mxpeg_helper.h
+SOURCES_image2 = image2.c image_helper.h mxpeg_helper.h
SOURCES_demux_stl = stl.c
libasf_plugin_la_SOURCES = asf/asf.c asf/libasf.c asf/libasf.h asf/libasf_guid.h
@@ -174,6 +175,7 @@ libvlc_LTLIBRARIES += \
libwav_plugin.la \
libxa_plugin.la \
libimage_plugin.la \
+ libimage2_plugin.la \
libdemux_stl_plugin.la \
$(NULL)
diff --git a/modules/demux/image.c b/modules/demux/image.c
index 672e7ba..6c7397d 100644
--- a/modules/demux/image.c
+++ b/modules/demux/image.c
@@ -33,7 +33,7 @@
#include <vlc_plugin.h>
#include <vlc_demux.h>
#include <vlc_image.h>
-#include "mxpeg_helper.h"
+#include "image_helper.h"
/*****************************************************************************
* Module descriptor
@@ -273,313 +273,26 @@ static int Control(demux_t *demux, int query, va_list args)
}
}
-static bool IsBmp(stream_t *s)
-{
- const uint8_t *header;
- if (stream_Peek(s, &header, 18) < 18)
- return false;
- if (memcmp(header, "BM", 2) &&
- memcmp(header, "BA", 2) &&
- memcmp(header, "CI", 2) &&
- memcmp(header, "CP", 2) &&
- memcmp(header, "IC", 2) &&
- memcmp(header, "PT", 2))
- return false;
- uint32_t file_size = GetDWLE(&header[2]);
- uint32_t data_offset = GetDWLE(&header[10]);
- uint32_t header_size = GetDWLE(&header[14]);
- if (file_size != 14 && file_size != 14 + header_size &&
- file_size <= data_offset)
- return false;
- if (data_offset < header_size + 14)
- return false;
- if (header_size != 12 && header_size < 40)
- return false;
- return true;
-}
-
-static bool IsPcx(stream_t *s)
-{
- const uint8_t *header;
- if (stream_Peek(s, &header, 66) < 66)
- return false;
- if (header[0] != 0x0A || /* marker */
- (header[1] != 0x00 && header[1] != 0x02 &&
- header[1] != 0x03 && header[1] != 0x05) || /* version */
- (header[2] != 0 && header[2] != 1) || /* encoding */
- (header[3] != 1 && header[3] != 2 &&
- header[3] != 4 && header[3] != 8) || /* bits per pixel per plane */
- header[64] != 0 || /* reserved */
- header[65] == 0 || header[65] > 4) /* plane count */
- return false;
- if (GetWLE(&header[4]) > GetWLE(&header[8]) || /* xmin vs xmax */
- GetWLE(&header[6]) > GetWLE(&header[10])) /* ymin vs ymax */
- return false;
- return true;
-}
-
-static bool IsLbm(stream_t *s)
-{
- const uint8_t *header;
- if (stream_Peek(s, &header, 12) < 12)
- return false;
- if (memcmp(&header[0], "FORM", 4) ||
- GetDWBE(&header[4]) <= 4 ||
- (memcmp(&header[8], "ILBM", 4) && memcmp(&header[8], "PBM ", 4)))
- return false;
- return true;
-}
-static bool IsPnmBlank(uint8_t v)
-{
- return v == ' ' || v == '\t' || v == '\r' || v == '\n';
-}
-static bool IsPnm(stream_t *s)
-{
- const uint8_t *header;
- int size = stream_Peek(s, &header, 256);
- if (size < 3)
- return false;
- if (header[0] != 'P' ||
- header[1] < '1' || header[1] > '6' ||
- !IsPnmBlank(header[2]))
- return false;
-
- int number_count = 0;
- for (int i = 3, parsing_number = 0; i < size && number_count < 2; i++) {
- if (IsPnmBlank(header[i])) {
- if (parsing_number) {
- parsing_number = 0;
- number_count++;
- }
- } else {
- if (header[i] < '0' || header[i] > '9')
- break;
- parsing_number = 1;
- }
- }
- if (number_count < 2)
- return false;
- return true;
-}
-
-static uint8_t FindJpegMarker(int *position, const uint8_t *data, int size)
-{
- for (int i = *position; i + 1 < size; i++) {
- if (data[i + 0] != 0xff || data[i + 1] == 0x00)
- return 0xff;
- if (data[i + 1] != 0xff) {
- *position = i + 2;
- return data[i + 1];
- }
- }
- return 0xff;
-}
-static bool IsJfif(stream_t *s)
-{
- const uint8_t *header;
- int size = stream_Peek(s, &header, 256);
- int position = 0;
-
- if (FindJpegMarker(&position, header, size) != 0xd8)
- return false;
- if (FindJpegMarker(&position, header, size) != 0xe0)
- return false;
- position += 2; /* Skip size */
- if (position + 5 > size)
- return false;
- if (memcmp(&header[position], "JFIF\0", 5))
- return false;
- return true;
-}
-
-static bool IsSpiff(stream_t *s)
-{
- const uint8_t *header;
- if (stream_Peek(s, &header, 36) < 36) /* SPIFF header size */
- return false;
- if (header[0] != 0xff || header[1] != 0xd8 ||
- header[2] != 0xff || header[3] != 0xe8)
- return false;
- if (memcmp(&header[6], "SPIFF\0", 6))
- return false;
- return true;
-}
-
-static bool IsExif(stream_t *s)
-{
- const uint8_t *header;
- int size = stream_Peek(s, &header, 256);
- int position = 0;
-
- if (FindJpegMarker(&position, header, size) != 0xd8)
- return false;
- if (FindJpegMarker(&position, header, size) != 0xe1)
- return false;
- position += 2; /* Skip size */
- if (position + 5 > size)
- return false;
- if (memcmp(&header[position], "Exif\0", 5))
- return false;
- return true;
-}
-
-static bool IsTarga(stream_t *s)
-{
- /* The header is not enough to ensure proper detection, we need
- * to have a look at the footer. But doing so can be slow. So
- * try to avoid it when possible */
- const uint8_t *header;
- if (stream_Peek(s, &header, 18) < 18) /* Targa fixed header */
- return false;
- if (header[1] > 1) /* Color Map Type */
- return false;
- if ((header[1] != 0 || header[3 + 4] != 0) &&
- header[3 + 4] != 8 &&
- header[3 + 4] != 15 && header[3 + 4] != 16 &&
- header[3 + 4] != 24 && header[3 + 4] != 32)
- return false;
- if ((header[2] > 3 && header[2] < 9) || header[2] > 11) /* Image Type */
- return false;
- if (GetWLE(&header[8 + 4]) <= 0 || /* Width */
- GetWLE(&header[8 + 6]) <= 0) /* Height */
- return false;
- if (header[8 + 8] != 8 &&
- header[8 + 8] != 15 && header[8 + 8] != 16 &&
- header[8 + 8] != 24 && header[8 + 8] != 32)
- return false;
- if (header[8 + 9] & 0xc0) /* Reserved bits */
- return false;
-
- const int64_t size = stream_Size(s);
- if (size <= 18 + 26)
- return false;
- bool can_seek;
- if (stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek)
- return false;
-
- const int64_t position = stream_Tell(s);
- if (stream_Seek(s, size - 26))
- return false;
-
- const uint8_t *footer;
- bool is_targa = stream_Peek(s, &footer, 26) >= 26 &&
- !memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18);
- stream_Seek(s, position);
- return is_targa;
-}
-
-typedef struct {
- vlc_fourcc_t codec;
- int marker_size;
- const uint8_t marker[14];
- bool (*detect)(stream_t *s);
-} image_format_t;
-
-#define VLC_CODEC_XCF VLC_FOURCC('X', 'C', 'F', ' ')
-#define VLC_CODEC_LBM VLC_FOURCC('L', 'B', 'M', ' ')
-static const image_format_t formats[] = {
- { .codec = VLC_CODEC_XCF,
- .marker_size = 9 + 4 + 1,
- .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
- 'f', 'i', 'l', 'e', '\0' }
- },
- { .codec = VLC_CODEC_XCF,
- .marker_size = 9 + 4 + 1,
- .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
- 'v', '0', '0', '1', '\0' }
- },
- { .codec = VLC_CODEC_XCF,
- .marker_size = 9 + 4 + 1,
- .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
- 'v', '0', '0', '2', '\0' }
- },
- { .codec = VLC_CODEC_PNG,
- .marker_size = 8,
- .marker = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
- },
- { .codec = VLC_CODEC_GIF,
- .marker_size = 6,
- .marker = { 'G', 'I', 'F', '8', '7', 'a' }
- },
- { .codec = VLC_CODEC_GIF,
- .marker_size = 6,
- .marker = { 'G', 'I', 'F', '8', '9', 'a' }
- },
- /* XXX TIFF detection may be a bit weak */
- { .codec = VLC_CODEC_TIFF,
- .marker_size = 4,
- .marker = { 'I', 'I', 0x2a, 0x00 },
- },
- { .codec = VLC_CODEC_TIFF,
- .marker_size = 4,
- .marker = { 'M', 'M', 0x00, 0x2a },
- },
- { .codec = VLC_CODEC_BMP,
- .detect = IsBmp,
- },
- { .codec = VLC_CODEC_PCX,
- .detect = IsPcx,
- },
- { .codec = VLC_CODEC_LBM,
- .detect = IsLbm,
- },
- { .codec = VLC_CODEC_PNM,
- .detect = IsPnm,
- },
- { .codec = VLC_CODEC_MXPEG,
- .detect = IsMxpeg,
- },
- { .codec = VLC_CODEC_JPEG,
- .detect = IsJfif,
- },
- { .codec = VLC_CODEC_JPEG,
- .detect = IsSpiff,
- },
- { .codec = VLC_CODEC_JPEG,
- .detect = IsExif,
- },
- { .codec = VLC_CODEC_TARGA,
- .detect = IsTarga,
- },
- { .codec = 0 }
-};
-
static int Open(vlc_object_t *object)
{
demux_t *demux = (demux_t*)object;
/* Detect the image type */
- const image_format_t *img;
-
- const uint8_t *peek;
- int peek_size = 0;
- for (int i = 0; ; i++) {
- img = &formats[i];
- if (!img->codec)
- return VLC_EGENERIC;
+ vlc_fourcc_t codec = Content2Fourcc(demux->s);
+ if( !codec )
+ return VLC_EGENERIC;
- if (img->detect) {
- if (img->detect(demux->s))
- break;
- } else {
- if (peek_size < img->marker_size)
- peek_size = stream_Peek(demux->s, &peek, img->marker_size);
- if (peek_size >= img->marker_size &&
- !memcmp(peek, img->marker, img->marker_size))
- break;
- }
- }
msg_Dbg(demux, "Detected image: %s",
- vlc_fourcc_GetDescription(VIDEO_ES, img->codec));
+ vlc_fourcc_GetDescription(VIDEO_ES, codec));
- if( img->codec == VLC_CODEC_MXPEG )
+ if( codec == VLC_CODEC_MXPEG )
{
return VLC_EGENERIC; //let avformat demux this file
}
/* Load and if selected decode */
es_format_t fmt;
- es_format_Init(&fmt, VIDEO_ES, img->codec);
+ es_format_Init(&fmt, VIDEO_ES, codec);
fmt.video.i_chroma = fmt.i_codec;
block_t *data = Load(demux);
diff --git a/modules/demux/image2.c b/modules/demux/image2.c
new file mode 100644
index 0000000..08c2dc2
--- /dev/null
+++ b/modules/demux/image2.c
@@ -0,0 +1,719 @@
+/*****************************************************************************
+ * image2.c : image plugin for reading/writing facilities
+ *****************************************************************************
+ * Copyright (C) 2004-2007 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Author: Gildas Bazin <gbazin at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/**
+ * \file
+ * This file contains the functions to handle the image_handler_t type
+ */
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_meta.h>
+#include <vlc_filter.h>
+#include <vlc_es.h>
+#include <vlc_image.h>
+#include <vlc_stream.h>
+#include <vlc_fs.h>
+#include <vlc_sout.h>
+#include <vlc_modules.h>
+#include <image_helper.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+ set_description(N_("Image facilities"))
+ set_capability("image provider", 10)
+ set_callbacks(Open, Close)
+vlc_module_end()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+static picture_t *ImageRead( image_handler_t *, block_t *,
+ video_format_t *, video_format_t * );
+static picture_t *ImageReadUrl( image_handler_t *, const char *,
+ video_format_t *, video_format_t * );
+static block_t *ImageWrite( image_handler_t *, picture_t *,
+ video_format_t *, video_format_t * );
+static int ImageWriteUrl( image_handler_t *, picture_t *,
+ video_format_t *, video_format_t *, const char * );
+
+static picture_t *ImageConvert( image_handler_t *, picture_t *,
+ video_format_t *, video_format_t * );
+static picture_t *ImageFilter( image_handler_t *, picture_t *,
+ video_format_t *, const char *psz_module );
+
+static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
+static void DeleteDecoder( decoder_t * );
+static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
+ video_format_t * );
+static void DeleteEncoder( encoder_t * );
+static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
+ video_format_t *, const char * );
+static void DeleteFilter( filter_t * );
+
+static int Open(vlc_object_t *object)
+{
+ image_handler_t *p_image = (image_handler_t*)object;
+
+ p_image->pf_read = ImageRead;
+ p_image->pf_read_url = ImageReadUrl;
+ p_image->pf_write = ImageWrite;
+ p_image->pf_write_url = ImageWriteUrl;
+ p_image->pf_convert = ImageConvert;
+ p_image->pf_filter = ImageFilter;
+
+ return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *object)
+{
+ image_handler_t *p_image = (image_handler_t*)object;
+
+ if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
+ if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
+ if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
+
+ p_image->p_dec = NULL;
+ p_image->p_enc = NULL;
+ p_image->p_filter = NULL;
+}
+
+/**
+ * Read an image
+ *
+ */
+
+static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
+ video_format_t *p_fmt_in,
+ video_format_t *p_fmt_out )
+{
+ picture_t *p_pic = NULL, *p_tmp;
+
+ /* Check if we can reuse the current decoder */
+ if( p_image->p_dec &&
+ p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
+ {
+ DeleteDecoder( p_image->p_dec );
+ p_image->p_dec = 0;
+ }
+
+ /* Start a decoder */
+ if( !p_image->p_dec )
+ {
+ p_image->p_dec = CreateDecoder( p_image, p_fmt_in );
+ if( !p_image->p_dec ) return NULL;
+ }
+
+ p_block->i_pts = p_block->i_dts = mdate();
+ while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
+ != NULL )
+ {
+ if( p_pic != NULL )
+ picture_Release( p_pic );
+ p_pic = p_tmp;
+ }
+
+ if( p_pic == NULL )
+ {
+ msg_Warn( p_image, "no image decoded" );
+ return 0;
+ }
+
+ if( !p_fmt_out->i_chroma )
+ p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
+ if( !p_fmt_out->i_width && p_fmt_out->i_height )
+ p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
+ p_image->p_dec->fmt_out.video.i_sar_num *
+ p_fmt_out->i_height /
+ p_image->p_dec->fmt_out.video.i_height /
+ p_image->p_dec->fmt_out.video.i_sar_den;
+
+ if( !p_fmt_out->i_height && p_fmt_out->i_width )
+ p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
+ p_image->p_dec->fmt_out.video.i_sar_den *
+ p_fmt_out->i_width /
+ p_image->p_dec->fmt_out.video.i_width /
+ p_image->p_dec->fmt_out.video.i_sar_num;
+ if( !p_fmt_out->i_width )
+ p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
+ if( !p_fmt_out->i_height )
+ p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
+
+ /* Check if we need chroma conversion or resizing */
+ if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
+ p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
+ p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
+ {
+ if( p_image->p_filter )
+ if( p_image->p_filter->fmt_in.video.i_chroma !=
+ p_image->p_dec->fmt_out.video.i_chroma ||
+ p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
+ {
+ /* We need to restart a new filter */
+ DeleteFilter( p_image->p_filter );
+ p_image->p_filter = 0;
+ }
+
+ /* Start a filter */
+ if( !p_image->p_filter )
+ {
+ p_image->p_filter =
+ CreateFilter( p_image, &p_image->p_dec->fmt_out,
+ p_fmt_out, NULL );
+
+ if( !p_image->p_filter )
+ {
+ picture_Release( p_pic );
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Filters should handle on-the-fly size changes */
+ p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
+ p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
+ p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
+ p_image->p_filter->fmt_out.video = *p_fmt_out;
+ }
+
+ p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+ *p_fmt_out = p_image->p_filter->fmt_out.video;
+ }
+ else *p_fmt_out = p_image->p_dec->fmt_out.video;
+
+ return p_pic;
+}
+
+static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
+ video_format_t *p_fmt_in,
+ video_format_t *p_fmt_out )
+{
+ block_t *p_block;
+ picture_t *p_pic;
+ stream_t *p_stream = NULL;
+ int i_size;
+
+ p_stream = stream_UrlNew( p_image, psz_url );
+
+ if( !p_stream )
+ {
+ msg_Dbg( p_image, "could not open %s for reading",
+ psz_url );
+ return NULL;
+ }
+
+ // first off, try an early chroma detection based on content
+ if( !p_fmt_in->i_chroma )
+ {
+ p_fmt_in->i_chroma = Content2Fourcc( p_stream );
+ }
+
+ i_size = stream_Size( p_stream );
+
+ p_block = block_Alloc( i_size );
+
+ stream_Read( p_stream, p_block->p_buffer, i_size );
+
+ if( !p_fmt_in->i_chroma )
+ {
+ char *psz_mime = NULL;
+ stream_Control( p_stream, STREAM_GET_CONTENT_TYPE, &psz_mime );
+ if( psz_mime )
+ p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
+ free( psz_mime );
+ }
+ stream_Delete( p_stream );
+
+ if( !p_fmt_in->i_chroma )
+ {
+ /* Try to guess format from file name */
+ p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
+ }
+
+ p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
+
+ return p_pic;
+}
+
+/**
+ * Write an image
+ *
+ */
+
+static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
+ video_format_t *p_fmt_in,
+ video_format_t *p_fmt_out )
+{
+ block_t *p_block;
+
+ /* Check if we can reuse the current encoder */
+ if( p_image->p_enc &&
+ ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
+ p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
+ p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
+ {
+ DeleteEncoder( p_image->p_enc );
+ p_image->p_enc = 0;
+ }
+
+ /* Start an encoder */
+ if( !p_image->p_enc )
+ {
+ p_image->p_enc = CreateEncoder( p_image,
+ p_fmt_in, p_fmt_out );
+ if( !p_image->p_enc ) return NULL;
+ }
+
+ /* Check if we need chroma conversion or resizing */
+ if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
+ p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
+ p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height )
+ {
+ picture_t *p_tmp_pic;
+
+ if( p_image->p_filter )
+ if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
+ p_image->p_filter->fmt_out.video.i_chroma !=
+ p_image->p_enc->fmt_in.video.i_chroma )
+ {
+ /* We need to restart a new filter */
+ DeleteFilter( p_image->p_filter );
+ p_image->p_filter = 0;
+ }
+
+ /* Start a filter */
+ if( !p_image->p_filter )
+ {
+ es_format_t fmt_in;
+ es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
+ fmt_in.video = *p_fmt_in;
+
+ p_image->p_filter =
+ CreateFilter( p_image, &fmt_in,
+ &p_image->p_enc->fmt_in.video, NULL );
+
+ if( !p_image->p_filter )
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Filters should handle on-the-fly size changes */
+ p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
+ p_image->p_filter->fmt_out.video = *p_fmt_in;
+ p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
+ p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
+ }
+
+ picture_Hold( p_pic );
+
+ p_tmp_pic =
+ p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+
+ if( likely(p_tmp_pic != NULL) )
+ {
+ p_block = p_image->p_enc->pf_encode_video( p_image->p_enc,
+ p_tmp_pic );
+ p_image->p_filter->pf_video_buffer_del( p_image->p_filter,
+ p_tmp_pic );
+ }
+ else
+ p_block = NULL;
+ }
+ else
+ {
+ p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
+ }
+
+ if( !p_block )
+ {
+ msg_Dbg( p_image, "no image encoded" );
+ return 0;
+ }
+
+ return p_block;
+}
+
+static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
+ video_format_t *p_fmt_in, video_format_t *p_fmt_out,
+ const char *psz_url )
+{
+ block_t *p_block;
+ FILE *file;
+
+ if( !p_fmt_out->i_chroma )
+ {
+ /* Try to guess format from file name */
+ p_fmt_out->i_chroma = image_Ext2Fourcc( psz_url );
+ }
+
+ file = vlc_fopen( psz_url, "wb" );
+ if( !file )
+ {
+ msg_Err( p_image, "%s: %m", psz_url );
+ return VLC_EGENERIC;
+ }
+
+ p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
+
+ int err = 0;
+ if( p_block )
+ {
+ if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, file ) != 1 )
+ err = errno;
+ block_Release( p_block );
+ }
+
+ if( fclose( file ) && !err )
+ err = errno;
+
+ if( err )
+ {
+ errno = err;
+ msg_Err( p_image, "%s: %m", psz_url );
+ }
+
+ return err ? VLC_EGENERIC : VLC_SUCCESS;
+}
+
+/**
+ * Convert an image to a different format
+ *
+ */
+
+static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
+ video_format_t *p_fmt_in,
+ video_format_t *p_fmt_out )
+{
+ picture_t *p_pif;
+
+ if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
+ p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
+ p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
+ p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
+ {
+ p_fmt_out->i_width =
+ p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
+ p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
+ p_fmt_out->i_visible_width =
+ p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
+ p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
+ p_fmt_out->i_sar_num;
+ }
+
+ if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
+ if( !p_fmt_out->i_width )
+ p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
+ if( !p_fmt_out->i_height )
+ p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
+ if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
+ if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
+
+ if( p_image->p_filter )
+ if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
+ p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
+ {
+ /* We need to restart a new filter */
+ DeleteFilter( p_image->p_filter );
+ p_image->p_filter = NULL;
+ }
+
+ /* Start a filter */
+ if( !p_image->p_filter )
+ {
+ es_format_t fmt_in;
+ es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
+ fmt_in.video = *p_fmt_in;
+
+ p_image->p_filter =
+ CreateFilter( p_image, &fmt_in, p_fmt_out, NULL );
+
+ if( !p_image->p_filter )
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Filters should handle on-the-fly size changes */
+ p_image->p_filter->fmt_in.video = *p_fmt_in;
+ p_image->p_filter->fmt_out.video = *p_fmt_out;
+ }
+
+ picture_Hold( p_pic );
+
+ p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+
+ if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
+ p_fmt_in->i_width == p_fmt_out->i_width &&
+ p_fmt_in->i_height == p_fmt_out->i_height )
+ {
+ /* Duplicate image */
+ picture_Release( p_pif ); /* XXX: Better fix must be possible */
+ p_pif = p_image->p_filter->pf_video_buffer_new( p_image->p_filter );
+ if( p_pif )
+ picture_Copy( p_pif, p_pic );
+ }
+
+ return p_pif;
+}
+
+/**
+ * Filter an image with a psz_module filter
+ *
+ */
+
+static picture_t *ImageFilter( image_handler_t *p_image, picture_t *p_pic,
+ video_format_t *p_fmt, const char *psz_module )
+{
+ /* Start a filter */
+ if( !p_image->p_filter )
+ {
+ es_format_t fmt;
+ es_format_Init( &fmt, VIDEO_ES, p_fmt->i_chroma );
+ fmt.video = *p_fmt;
+
+ p_image->p_filter =
+ CreateFilter( p_image, &fmt, &fmt.video, psz_module );
+
+ if( !p_image->p_filter )
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Filters should handle on-the-fly size changes */
+ p_image->p_filter->fmt_in.video = *p_fmt;
+ p_image->p_filter->fmt_out.video = *p_fmt;
+ }
+
+ picture_Hold( p_pic );
+
+ return p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+}
+
+static picture_t *video_new_buffer( decoder_t *p_dec )
+{
+ p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
+ return picture_NewFromFormat( &p_dec->fmt_out.video );
+}
+
+static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
+{
+ (void)p_dec;
+ picture_Release( p_pic );
+}
+
+static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
+{
+ (void)p_dec;
+ picture_Hold( p_pic );
+}
+
+static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
+{
+ (void)p_dec;
+ picture_Release( p_pic );
+}
+
+static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
+{
+ decoder_t *p_dec;
+
+ p_dec = vlc_object_create( p_this, sizeof( *p_dec ) );
+ if( p_dec == NULL )
+ return NULL;
+
+ p_dec->p_module = NULL;
+ es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
+ es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
+ p_dec->fmt_in.video = *fmt;
+ p_dec->b_pace_control = true;
+
+ p_dec->pf_vout_buffer_new = video_new_buffer;
+ p_dec->pf_vout_buffer_del = video_del_buffer;
+ p_dec->pf_picture_link = video_link_picture;
+ p_dec->pf_picture_unlink = video_unlink_picture;
+
+ /* Find a suitable decoder module */
+ p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
+ if( !p_dec->p_module )
+ {
+ msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
+ "VLC probably does not support this image format.",
+ (char*)&p_dec->fmt_in.i_codec );
+
+ DeleteDecoder( p_dec );
+ return NULL;
+ }
+
+ return p_dec;
+}
+
+static void DeleteDecoder( decoder_t * p_dec )
+{
+ if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
+
+ es_format_Clean( &p_dec->fmt_in );
+ es_format_Clean( &p_dec->fmt_out );
+
+ if( p_dec->p_description )
+ vlc_meta_Delete( p_dec->p_description );
+
+ vlc_object_release( p_dec );
+ p_dec = NULL;
+}
+
+static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
+ video_format_t *fmt_out )
+{
+ encoder_t *p_enc;
+
+ p_enc = sout_EncoderCreate( p_this );
+ if( p_enc == NULL )
+ return NULL;
+
+ p_enc->p_module = NULL;
+ es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
+ p_enc->fmt_in.video = *fmt_in;
+ if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
+ {
+ p_enc->fmt_in.video.i_width = fmt_out->i_width;
+ p_enc->fmt_in.video.i_height = fmt_out->i_height;
+
+ if( fmt_out->i_visible_width > 0 &&
+ fmt_out->i_visible_height > 0 )
+ {
+ p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
+ p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
+ }
+ else
+ {
+ p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
+ p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
+ }
+ }
+ else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
+ fmt_out->i_sar_num * fmt_in->i_sar_den !=
+ fmt_out->i_sar_den * fmt_in->i_sar_num )
+ {
+ p_enc->fmt_in.video.i_width =
+ fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
+ fmt_in->i_sar_den / fmt_out->i_sar_num;
+ p_enc->fmt_in.video.i_visible_width =
+ fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
+ fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
+ }
+
+ p_enc->fmt_in.video.i_frame_rate = 25;
+ p_enc->fmt_in.video.i_frame_rate_base = 1;
+
+ es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
+ p_enc->fmt_out.video = *fmt_out;
+ p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
+ p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
+
+ /* Find a suitable decoder module */
+ p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
+ if( !p_enc->p_module )
+ {
+ msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
+ "VLC probably does not support this image format.",
+ (char*)&p_enc->fmt_out.i_codec );
+
+ DeleteEncoder( p_enc );
+ return NULL;
+ }
+ p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
+
+ return p_enc;
+}
+
+static void DeleteEncoder( encoder_t * p_enc )
+{
+ if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
+
+ es_format_Clean( &p_enc->fmt_in );
+ es_format_Clean( &p_enc->fmt_out );
+
+ vlc_object_release( p_enc );
+ p_enc = NULL;
+}
+
+static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
+ video_format_t *p_fmt_out,
+ const char *psz_module )
+{
+ filter_t *p_filter;
+
+ p_filter = vlc_object_create( p_this, sizeof(filter_t) );
+ p_filter->pf_video_buffer_new =
+ (picture_t *(*)(filter_t *))video_new_buffer;
+ p_filter->pf_video_buffer_del =
+ (void (*)(filter_t *, picture_t *))video_del_buffer;
+
+ p_filter->fmt_in = *p_fmt_in;
+ p_filter->fmt_out = *p_fmt_in;
+ p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
+ p_filter->fmt_out.video = *p_fmt_out;
+ p_filter->p_module = module_need( p_filter, "video filter2",
+ psz_module, false );
+
+ if( !p_filter->p_module )
+ {
+ msg_Dbg( p_filter, "no video filter found" );
+ DeleteFilter( p_filter );
+ return NULL;
+ }
+
+ return p_filter;
+}
+
+static void DeleteFilter( filter_t * p_filter )
+{
+ if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
+
+ es_format_Clean( &p_filter->fmt_in );
+ es_format_Clean( &p_filter->fmt_out );
+
+ vlc_object_release( p_filter );
+}
diff --git a/modules/demux/image_helper.h b/modules/demux/image_helper.h
new file mode 100644
index 0000000..7652a7d
--- /dev/null
+++ b/modules/demux/image_helper.h
@@ -0,0 +1,334 @@
+/*****************************************************************************
+ * image_helper.h: Image helper
+ *****************************************************************************
+ * Copyright (C) 2010 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_image.h>
+#include "mxpeg_helper.h"
+
+
+static bool IsBmp(stream_t *s)
+{
+ const uint8_t *header;
+ if (stream_Peek(s, &header, 18) < 18)
+ return false;
+ if (memcmp(header, "BM", 2) &&
+ memcmp(header, "BA", 2) &&
+ memcmp(header, "CI", 2) &&
+ memcmp(header, "CP", 2) &&
+ memcmp(header, "IC", 2) &&
+ memcmp(header, "PT", 2))
+ return false;
+ uint32_t file_size = GetDWLE(&header[2]);
+ uint32_t data_offset = GetDWLE(&header[10]);
+ uint32_t header_size = GetDWLE(&header[14]);
+ if (file_size != 14 && file_size != 14 + header_size &&
+ file_size <= data_offset)
+ return false;
+ if (data_offset < header_size + 14)
+ return false;
+ if (header_size != 12 && header_size < 40)
+ return false;
+ return true;
+}
+
+static bool IsPcx(stream_t *s)
+{
+ const uint8_t *header;
+ if (stream_Peek(s, &header, 66) < 66)
+ return false;
+ if (header[0] != 0x0A || /* marker */
+ (header[1] != 0x00 && header[1] != 0x02 &&
+ header[1] != 0x03 && header[1] != 0x05) || /* version */
+ (header[2] != 0 && header[2] != 1) || /* encoding */
+ (header[3] != 1 && header[3] != 2 &&
+ header[3] != 4 && header[3] != 8) || /* bits per pixel per plane */
+ header[64] != 0 || /* reserved */
+ header[65] == 0 || header[65] > 4) /* plane count */
+ return false;
+ if (GetWLE(&header[4]) > GetWLE(&header[8]) || /* xmin vs xmax */
+ GetWLE(&header[6]) > GetWLE(&header[10])) /* ymin vs ymax */
+ return false;
+ return true;
+}
+
+static bool IsLbm(stream_t *s)
+{
+ const uint8_t *header;
+ if (stream_Peek(s, &header, 12) < 12)
+ return false;
+ if (memcmp(&header[0], "FORM", 4) ||
+ GetDWBE(&header[4]) <= 4 ||
+ (memcmp(&header[8], "ILBM", 4) && memcmp(&header[8], "PBM ", 4)))
+ return false;
+ return true;
+}
+static bool IsPnmBlank(uint8_t v)
+{
+ return v == ' ' || v == '\t' || v == '\r' || v == '\n';
+}
+static bool IsPnm(stream_t *s)
+{
+ const uint8_t *header;
+ int size = stream_Peek(s, &header, 256);
+ if (size < 3)
+ return false;
+ if (header[0] != 'P' ||
+ header[1] < '1' || header[1] > '6' ||
+ !IsPnmBlank(header[2]))
+ return false;
+
+ int number_count = 0;
+ for (int i = 3, parsing_number = 0; i < size && number_count < 2; i++) {
+ if (IsPnmBlank(header[i])) {
+ if (parsing_number) {
+ parsing_number = 0;
+ number_count++;
+ }
+ } else {
+ if (header[i] < '0' || header[i] > '9')
+ break;
+ parsing_number = 1;
+ }
+ }
+ if (number_count < 2)
+ return false;
+ return true;
+}
+
+static uint8_t FindJpegMarker(int *position, const uint8_t *data, int size)
+{
+ for (int i = *position; i + 1 < size; i++) {
+ if (data[i + 0] != 0xff || data[i + 1] == 0x00)
+ return 0xff;
+ if (data[i + 1] != 0xff) {
+ *position = i + 2;
+ return data[i + 1];
+ }
+ }
+ return 0xff;
+}
+static bool IsJfif(stream_t *s)
+{
+ const uint8_t *header;
+ int size = stream_Peek(s, &header, 256);
+ int position = 0;
+
+ if (FindJpegMarker(&position, header, size) != 0xd8)
+ return false;
+ if (FindJpegMarker(&position, header, size) != 0xe0)
+ return false;
+ position += 2; /* Skip size */
+ if (position + 5 > size)
+ return false;
+ if (memcmp(&header[position], "JFIF\0", 5))
+ return false;
+ return true;
+}
+
+static bool IsSpiff(stream_t *s)
+{
+ const uint8_t *header;
+ if (stream_Peek(s, &header, 36) < 36) /* SPIFF header size */
+ return false;
+ if (header[0] != 0xff || header[1] != 0xd8 ||
+ header[2] != 0xff || header[3] != 0xe8)
+ return false;
+ if (memcmp(&header[6], "SPIFF\0", 6))
+ return false;
+ return true;
+}
+
+static bool IsExif(stream_t *s)
+{
+ const uint8_t *header;
+ int size = stream_Peek(s, &header, 256);
+ int position = 0;
+
+ if (FindJpegMarker(&position, header, size) != 0xd8)
+ return false;
+ if (FindJpegMarker(&position, header, size) != 0xe1)
+ return false;
+ position += 2; /* Skip size */
+ if (position + 5 > size)
+ return false;
+ if (memcmp(&header[position], "Exif\0", 5))
+ return false;
+ return true;
+}
+
+static bool IsTarga(stream_t *s)
+{
+ /* The header is not enough to ensure proper detection, we need
+ * to have a look at the footer. But doing so can be slow. So
+ * try to avoid it when possible */
+ const uint8_t *header;
+ if (stream_Peek(s, &header, 18) < 18) /* Targa fixed header */
+ return false;
+ if (header[1] > 1) /* Color Map Type */
+ return false;
+ if ((header[1] != 0 || header[3 + 4] != 0) &&
+ header[3 + 4] != 8 &&
+ header[3 + 4] != 15 && header[3 + 4] != 16 &&
+ header[3 + 4] != 24 && header[3 + 4] != 32)
+ return false;
+ if ((header[2] > 3 && header[2] < 9) || header[2] > 11) /* Image Type */
+ return false;
+ if (GetWLE(&header[8 + 4]) <= 0 || /* Width */
+ GetWLE(&header[8 + 6]) <= 0) /* Height */
+ return false;
+ if (header[8 + 8] != 8 &&
+ header[8 + 8] != 15 && header[8 + 8] != 16 &&
+ header[8 + 8] != 24 && header[8 + 8] != 32)
+ return false;
+ if (header[8 + 9] & 0xc0) /* Reserved bits */
+ return false;
+
+ const int64_t size = stream_Size(s);
+ if (size <= 18 + 26)
+ return false;
+ bool can_seek;
+ if (stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek)
+ return false;
+
+ const int64_t position = stream_Tell(s);
+ if (stream_Seek(s, size - 26))
+ return false;
+
+ const uint8_t *footer;
+ bool is_targa = stream_Peek(s, &footer, 26) >= 26 &&
+ !memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18);
+ stream_Seek(s, position);
+ return is_targa;
+}
+
+typedef struct {
+ vlc_fourcc_t codec;
+ int marker_size;
+ const uint8_t marker[14];
+ bool (*detect)(stream_t *s);
+} image_format_t;
+
+#define VLC_CODEC_XCF VLC_FOURCC('X', 'C', 'F', ' ')
+#define VLC_CODEC_LBM VLC_FOURCC('L', 'B', 'M', ' ')
+static const image_format_t formats[] = {
+ { .codec = VLC_CODEC_XCF,
+ .marker_size = 9 + 4 + 1,
+ .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
+ 'f', 'i', 'l', 'e', '\0' }
+ },
+ { .codec = VLC_CODEC_XCF,
+ .marker_size = 9 + 4 + 1,
+ .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
+ 'v', '0', '0', '1', '\0' }
+ },
+ { .codec = VLC_CODEC_XCF,
+ .marker_size = 9 + 4 + 1,
+ .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
+ 'v', '0', '0', '2', '\0' }
+ },
+ { .codec = VLC_CODEC_PNG,
+ .marker_size = 8,
+ .marker = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
+ },
+ { .codec = VLC_CODEC_GIF,
+ .marker_size = 6,
+ .marker = { 'G', 'I', 'F', '8', '7', 'a' }
+ },
+ { .codec = VLC_CODEC_GIF,
+ .marker_size = 6,
+ .marker = { 'G', 'I', 'F', '8', '9', 'a' }
+ },
+ /* XXX TIFF detection may be a bit weak */
+ { .codec = VLC_CODEC_TIFF,
+ .marker_size = 4,
+ .marker = { 'I', 'I', 0x2a, 0x00 },
+ },
+ { .codec = VLC_CODEC_TIFF,
+ .marker_size = 4,
+ .marker = { 'M', 'M', 0x00, 0x2a },
+ },
+ { .codec = VLC_CODEC_BMP,
+ .detect = IsBmp,
+ },
+ { .codec = VLC_CODEC_PCX,
+ .detect = IsPcx,
+ },
+ { .codec = VLC_CODEC_LBM,
+ .detect = IsLbm,
+ },
+ { .codec = VLC_CODEC_PNM,
+ .detect = IsPnm,
+ },
+ { .codec = VLC_CODEC_MXPEG,
+ .detect = IsMxpeg,
+ },
+ { .codec = VLC_CODEC_JPEG,
+ .detect = IsJfif,
+ },
+ { .codec = VLC_CODEC_JPEG,
+ .detect = IsSpiff,
+ },
+ { .codec = VLC_CODEC_JPEG,
+ .detect = IsExif,
+ },
+ { .codec = VLC_CODEC_TARGA,
+ .detect = IsTarga,
+ },
+ { .codec = 0 }
+};
+
+static vlc_fourcc_t Content2Fourcc( stream_t *s )
+{
+ /* Detect the image type */
+ const image_format_t *img;
+
+ const uint8_t *peek;
+ int peek_size = 0;
+ for (int i = 0; ; i++) {
+ img = &formats[i];
+ if (!img->codec)
+ return 0;
+
+ if (img->detect) {
+ if (img->detect(s))
+ break;
+ } else {
+ if (peek_size < img->marker_size)
+ peek_size = stream_Peek(s, &peek, img->marker_size);
+ if (peek_size >= img->marker_size &&
+ !memcmp(peek, img->marker, img->marker_size))
+ break;
+ }
+ }
+ msg_Dbg(s, "Detected image: %s",
+ vlc_fourcc_GetDescription(VIDEO_ES, img->codec));
+ return img->codec;
+}
diff --git a/src/misc/image.c b/src/misc/image.c
index 2ce3f9c..65aaf23 100644
--- a/src/misc/image.c
+++ b/src/misc/image.c
@@ -37,43 +37,10 @@
#include <errno.h>
#include <vlc_common.h>
-#include <vlc_codec.h>
-#include <vlc_meta.h>
-#include <vlc_filter.h>
-#include <vlc_es.h>
#include <vlc_image.h>
-#include <vlc_stream.h>
-#include <vlc_fs.h>
-#include <vlc_sout.h>
#include <libvlc.h>
#include <vlc_modules.h>
-static picture_t *ImageRead( image_handler_t *, block_t *,
- video_format_t *, video_format_t * );
-static picture_t *ImageReadUrl( image_handler_t *, const char *,
- video_format_t *, video_format_t * );
-static block_t *ImageWrite( image_handler_t *, picture_t *,
- video_format_t *, video_format_t * );
-static int ImageWriteUrl( image_handler_t *, picture_t *,
- video_format_t *, video_format_t *, const char * );
-
-static picture_t *ImageConvert( image_handler_t *, picture_t *,
- video_format_t *, video_format_t * );
-static picture_t *ImageFilter( image_handler_t *, picture_t *,
- video_format_t *, const char *psz_module );
-
-static decoder_t *CreateDecoder( vlc_object_t *, video_format_t * );
-static void DeleteDecoder( decoder_t * );
-static encoder_t *CreateEncoder( vlc_object_t *, video_format_t *,
- video_format_t * );
-static void DeleteEncoder( encoder_t * );
-static filter_t *CreateFilter( vlc_object_t *, es_format_t *,
- video_format_t *, const char * );
-static void DeleteFilter( filter_t * );
-
-vlc_fourcc_t image_Type2Fourcc( const char * );
-vlc_fourcc_t image_Ext2Fourcc( const char * );
-/*static const char *Fourcc2Ext( vlc_fourcc_t );*/
#undef image_HandlerCreate
/**
@@ -82,18 +49,19 @@ vlc_fourcc_t image_Ext2Fourcc( const char * );
*/
image_handler_t *image_HandlerCreate( vlc_object_t *p_this )
{
- image_handler_t *p_image = calloc( 1, sizeof(image_handler_t) );
+ image_handler_t *p_image;
+
+ p_image = vlc_custom_create( p_this, sizeof( *p_image ), "image" );
if( !p_image )
return NULL;
- p_image->p_parent = p_this;
-
- p_image->pf_read = ImageRead;
- p_image->pf_read_url = ImageReadUrl;
- p_image->pf_write = ImageWrite;
- p_image->pf_write_url = ImageWriteUrl;
- p_image->pf_convert = ImageConvert;
- p_image->pf_filter = ImageFilter;
+ p_image->p_module = module_need( p_image, "image provider", NULL, false );
+ if( !p_image->p_module )
+ {
+ vlc_object_release( p_image );
+ msg_Err( p_this, "image provider not found" );
+ return NULL;
+ }
return p_image;
}
@@ -106,422 +74,8 @@ void image_HandlerDelete( image_handler_t *p_image )
{
if( !p_image ) return;
- if( p_image->p_dec ) DeleteDecoder( p_image->p_dec );
- if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
- if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
-
- free( p_image );
- p_image = NULL;
-}
-
-/**
- * Read an image
- *
- */
-
-static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
- video_format_t *p_fmt_in,
- video_format_t *p_fmt_out )
-{
- picture_t *p_pic = NULL, *p_tmp;
-
- /* Check if we can reuse the current decoder */
- if( p_image->p_dec &&
- p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
- {
- DeleteDecoder( p_image->p_dec );
- p_image->p_dec = 0;
- }
-
- /* Start a decoder */
- if( !p_image->p_dec )
- {
- p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
- if( !p_image->p_dec ) return NULL;
- }
-
- p_block->i_pts = p_block->i_dts = mdate();
- while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
- != NULL )
- {
- if( p_pic != NULL )
- picture_Release( p_pic );
- p_pic = p_tmp;
- }
-
- if( p_pic == NULL )
- {
- msg_Warn( p_image->p_parent, "no image decoded" );
- return 0;
- }
-
- if( !p_fmt_out->i_chroma )
- p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
- if( !p_fmt_out->i_width && p_fmt_out->i_height )
- p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
- p_image->p_dec->fmt_out.video.i_sar_num *
- p_fmt_out->i_height /
- p_image->p_dec->fmt_out.video.i_height /
- p_image->p_dec->fmt_out.video.i_sar_den;
-
- if( !p_fmt_out->i_height && p_fmt_out->i_width )
- p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
- p_image->p_dec->fmt_out.video.i_sar_den *
- p_fmt_out->i_width /
- p_image->p_dec->fmt_out.video.i_width /
- p_image->p_dec->fmt_out.video.i_sar_num;
- if( !p_fmt_out->i_width )
- p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
- if( !p_fmt_out->i_height )
- p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
-
- /* Check if we need chroma conversion or resizing */
- if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
- p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
- p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
- {
- if( p_image->p_filter )
- if( p_image->p_filter->fmt_in.video.i_chroma !=
- p_image->p_dec->fmt_out.video.i_chroma ||
- p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
- {
- /* We need to restart a new filter */
- DeleteFilter( p_image->p_filter );
- p_image->p_filter = 0;
- }
-
- /* Start a filter */
- if( !p_image->p_filter )
- {
- p_image->p_filter =
- CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
- p_fmt_out, NULL );
-
- if( !p_image->p_filter )
- {
- picture_Release( p_pic );
- return NULL;
- }
- }
- else
- {
- /* Filters should handle on-the-fly size changes */
- p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
- p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
- p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
- p_image->p_filter->fmt_out.video = *p_fmt_out;
- }
-
- p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
- *p_fmt_out = p_image->p_filter->fmt_out.video;
- }
- else *p_fmt_out = p_image->p_dec->fmt_out.video;
-
- return p_pic;
-}
-
-static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
- video_format_t *p_fmt_in,
- video_format_t *p_fmt_out )
-{
- block_t *p_block;
- picture_t *p_pic;
- stream_t *p_stream = NULL;
- int i_size;
-
- p_stream = stream_UrlNew( p_image->p_parent, psz_url );
-
- if( !p_stream )
- {
- msg_Dbg( p_image->p_parent, "could not open %s for reading",
- psz_url );
- return NULL;
- }
-
- i_size = stream_Size( p_stream );
-
- p_block = block_Alloc( i_size );
-
- stream_Read( p_stream, p_block->p_buffer, i_size );
-
- if( !p_fmt_in->i_chroma )
- {
- char *psz_mime = NULL;
- stream_Control( p_stream, STREAM_GET_CONTENT_TYPE, &psz_mime );
- if( psz_mime )
- p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
- free( psz_mime );
- }
- stream_Delete( p_stream );
-
- if( !p_fmt_in->i_chroma )
- {
- /* Try to guess format from file name */
- p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
- }
-
- p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );
-
- return p_pic;
-}
-
-/**
- * Write an image
- *
- */
-
-static block_t *ImageWrite( image_handler_t *p_image, picture_t *p_pic,
- video_format_t *p_fmt_in,
- video_format_t *p_fmt_out )
-{
- block_t *p_block;
-
- /* Check if we can reuse the current encoder */
- if( p_image->p_enc &&
- ( p_image->p_enc->fmt_out.i_codec != p_fmt_out->i_chroma ||
- p_image->p_enc->fmt_out.video.i_width != p_fmt_out->i_width ||
- p_image->p_enc->fmt_out.video.i_height != p_fmt_out->i_height ) )
- {
- DeleteEncoder( p_image->p_enc );
- p_image->p_enc = 0;
- }
-
- /* Start an encoder */
- if( !p_image->p_enc )
- {
- p_image->p_enc = CreateEncoder( p_image->p_parent,
- p_fmt_in, p_fmt_out );
- if( !p_image->p_enc ) return NULL;
- }
-
- /* Check if we need chroma conversion or resizing */
- if( p_image->p_enc->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
- p_image->p_enc->fmt_in.video.i_width != p_fmt_in->i_width ||
- p_image->p_enc->fmt_in.video.i_height != p_fmt_in->i_height )
- {
- picture_t *p_tmp_pic;
-
- if( p_image->p_filter )
- if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
- p_image->p_filter->fmt_out.video.i_chroma !=
- p_image->p_enc->fmt_in.video.i_chroma )
- {
- /* We need to restart a new filter */
- DeleteFilter( p_image->p_filter );
- p_image->p_filter = 0;
- }
-
- /* Start a filter */
- if( !p_image->p_filter )
- {
- es_format_t fmt_in;
- es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
- fmt_in.video = *p_fmt_in;
-
- p_image->p_filter =
- CreateFilter( p_image->p_parent, &fmt_in,
- &p_image->p_enc->fmt_in.video, NULL );
-
- if( !p_image->p_filter )
- {
- return NULL;
- }
- }
- else
- {
- /* Filters should handle on-the-fly size changes */
- p_image->p_filter->fmt_in.i_codec = p_fmt_in->i_chroma;
- p_image->p_filter->fmt_out.video = *p_fmt_in;
- p_image->p_filter->fmt_out.i_codec =p_image->p_enc->fmt_in.i_codec;
- p_image->p_filter->fmt_out.video = p_image->p_enc->fmt_in.video;
- }
-
- picture_Hold( p_pic );
-
- p_tmp_pic =
- p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
-
- if( likely(p_tmp_pic != NULL) )
- {
- p_block = p_image->p_enc->pf_encode_video( p_image->p_enc,
- p_tmp_pic );
- p_image->p_filter->pf_video_buffer_del( p_image->p_filter,
- p_tmp_pic );
- }
- else
- p_block = NULL;
- }
- else
- {
- p_block = p_image->p_enc->pf_encode_video( p_image->p_enc, p_pic );
- }
-
- if( !p_block )
- {
- msg_Dbg( p_image->p_parent, "no image encoded" );
- return 0;
- }
-
- return p_block;
-}
-
-static int ImageWriteUrl( image_handler_t *p_image, picture_t *p_pic,
- video_format_t *p_fmt_in, video_format_t *p_fmt_out,
- const char *psz_url )
-{
- block_t *p_block;
- FILE *file;
-
- if( !p_fmt_out->i_chroma )
- {
- /* Try to guess format from file name */
- p_fmt_out->i_chroma = image_Ext2Fourcc( psz_url );
- }
-
- file = vlc_fopen( psz_url, "wb" );
- if( !file )
- {
- msg_Err( p_image->p_parent, "%s: %m", psz_url );
- return VLC_EGENERIC;
- }
-
- p_block = ImageWrite( p_image, p_pic, p_fmt_in, p_fmt_out );
-
- int err = 0;
- if( p_block )
- {
- if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, file ) != 1 )
- err = errno;
- block_Release( p_block );
- }
-
- if( fclose( file ) && !err )
- err = errno;
-
- if( err )
- {
- errno = err;
- msg_Err( p_image->p_parent, "%s: %m", psz_url );
- }
-
- return err ? VLC_EGENERIC : VLC_SUCCESS;
-}
-
-/**
- * Convert an image to a different format
- *
- */
-
-static picture_t *ImageConvert( image_handler_t *p_image, picture_t *p_pic,
- video_format_t *p_fmt_in,
- video_format_t *p_fmt_out )
-{
- picture_t *p_pif;
-
- if( !p_fmt_out->i_width && !p_fmt_out->i_height &&
- p_fmt_out->i_sar_num && p_fmt_out->i_sar_den &&
- p_fmt_out->i_sar_num * p_fmt_in->i_sar_den !=
- p_fmt_out->i_sar_den * p_fmt_in->i_sar_num )
- {
- p_fmt_out->i_width =
- p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
- p_fmt_in->i_width / p_fmt_in->i_sar_den / p_fmt_out->i_sar_num;
- p_fmt_out->i_visible_width =
- p_fmt_in->i_sar_num * (int64_t)p_fmt_out->i_sar_den *
- p_fmt_in->i_visible_width / p_fmt_in->i_sar_den /
- p_fmt_out->i_sar_num;
- }
-
- if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_fmt_in->i_chroma;
- if( !p_fmt_out->i_width )
- p_fmt_out->i_width = p_fmt_out->i_visible_width = p_fmt_in->i_width;
- if( !p_fmt_out->i_height )
- p_fmt_out->i_height = p_fmt_out->i_visible_height = p_fmt_in->i_height;
- if( !p_fmt_out->i_sar_num ) p_fmt_out->i_sar_num = p_fmt_in->i_sar_num;
- if( !p_fmt_out->i_sar_den ) p_fmt_out->i_sar_den = p_fmt_in->i_sar_den;
-
- if( p_image->p_filter )
- if( p_image->p_filter->fmt_in.video.i_chroma != p_fmt_in->i_chroma ||
- p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
- {
- /* We need to restart a new filter */
- DeleteFilter( p_image->p_filter );
- p_image->p_filter = NULL;
- }
-
- /* Start a filter */
- if( !p_image->p_filter )
- {
- es_format_t fmt_in;
- es_format_Init( &fmt_in, VIDEO_ES, p_fmt_in->i_chroma );
- fmt_in.video = *p_fmt_in;
-
- p_image->p_filter =
- CreateFilter( p_image->p_parent, &fmt_in, p_fmt_out, NULL );
-
- if( !p_image->p_filter )
- {
- return NULL;
- }
- }
- else
- {
- /* Filters should handle on-the-fly size changes */
- p_image->p_filter->fmt_in.video = *p_fmt_in;
- p_image->p_filter->fmt_out.video = *p_fmt_out;
- }
-
- picture_Hold( p_pic );
-
- p_pif = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
-
- if( p_fmt_in->i_chroma == p_fmt_out->i_chroma &&
- p_fmt_in->i_width == p_fmt_out->i_width &&
- p_fmt_in->i_height == p_fmt_out->i_height )
- {
- /* Duplicate image */
- picture_Release( p_pif ); /* XXX: Better fix must be possible */
- p_pif = p_image->p_filter->pf_video_buffer_new( p_image->p_filter );
- if( p_pif )
- picture_Copy( p_pif, p_pic );
- }
-
- return p_pif;
-}
-
-/**
- * Filter an image with a psz_module filter
- *
- */
-
-static picture_t *ImageFilter( image_handler_t *p_image, picture_t *p_pic,
- video_format_t *p_fmt, const char *psz_module )
-{
- /* Start a filter */
- if( !p_image->p_filter )
- {
- es_format_t fmt;
- es_format_Init( &fmt, VIDEO_ES, p_fmt->i_chroma );
- fmt.video = *p_fmt;
-
- p_image->p_filter =
- CreateFilter( p_image->p_parent, &fmt, &fmt.video, psz_module );
-
- if( !p_image->p_filter )
- {
- return NULL;
- }
- }
- else
- {
- /* Filters should handle on-the-fly size changes */
- p_image->p_filter->fmt_in.video = *p_fmt;
- p_image->p_filter->fmt_out.video = *p_fmt;
- }
-
- picture_Hold( p_pic );
-
- return p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
+ module_unneed( p_image, p_image->p_module );
+ vlc_object_release( p_image );
}
/**
@@ -618,190 +172,3 @@ vlc_fourcc_t image_Mime2Fourcc( const char *psz_mime )
return 0;
}
-
-static picture_t *video_new_buffer( decoder_t *p_dec )
-{
- p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
- return picture_NewFromFormat( &p_dec->fmt_out.video );
-}
-
-static void video_del_buffer( decoder_t *p_dec, picture_t *p_pic )
-{
- (void)p_dec;
- picture_Release( p_pic );
-}
-
-static void video_link_picture( decoder_t *p_dec, picture_t *p_pic )
-{
- (void)p_dec;
- picture_Hold( p_pic );
-}
-
-static void video_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
-{
- (void)p_dec;
- picture_Release( p_pic );
-}
-
-static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt )
-{
- decoder_t *p_dec;
-
- p_dec = vlc_custom_create( p_this, sizeof( *p_dec ), "image decoder" );
- if( p_dec == NULL )
- return NULL;
-
- p_dec->p_module = NULL;
- es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma );
- es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
- p_dec->fmt_in.video = *fmt;
- p_dec->b_pace_control = true;
-
- p_dec->pf_vout_buffer_new = video_new_buffer;
- p_dec->pf_vout_buffer_del = video_del_buffer;
- p_dec->pf_picture_link = video_link_picture;
- p_dec->pf_picture_unlink = video_unlink_picture;
-
- /* Find a suitable decoder module */
- p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
- if( !p_dec->p_module )
- {
- msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. "
- "VLC probably does not support this image format.",
- (char*)&p_dec->fmt_in.i_codec );
-
- DeleteDecoder( p_dec );
- return NULL;
- }
-
- return p_dec;
-}
-
-static void DeleteDecoder( decoder_t * p_dec )
-{
- if( p_dec->p_module ) module_unneed( p_dec, p_dec->p_module );
-
- es_format_Clean( &p_dec->fmt_in );
- es_format_Clean( &p_dec->fmt_out );
-
- if( p_dec->p_description )
- vlc_meta_Delete( p_dec->p_description );
-
- vlc_object_release( p_dec );
- p_dec = NULL;
-}
-
-static encoder_t *CreateEncoder( vlc_object_t *p_this, video_format_t *fmt_in,
- video_format_t *fmt_out )
-{
- encoder_t *p_enc;
-
- p_enc = sout_EncoderCreate( p_this );
- if( p_enc == NULL )
- return NULL;
-
- p_enc->p_module = NULL;
- es_format_Init( &p_enc->fmt_in, VIDEO_ES, fmt_in->i_chroma );
- p_enc->fmt_in.video = *fmt_in;
- if( fmt_out->i_width > 0 && fmt_out->i_height > 0 )
- {
- p_enc->fmt_in.video.i_width = fmt_out->i_width;
- p_enc->fmt_in.video.i_height = fmt_out->i_height;
-
- if( fmt_out->i_visible_width > 0 &&
- fmt_out->i_visible_height > 0 )
- {
- p_enc->fmt_in.video.i_visible_width = fmt_out->i_visible_width;
- p_enc->fmt_in.video.i_visible_height = fmt_out->i_visible_height;
- }
- else
- {
- p_enc->fmt_in.video.i_visible_width = fmt_out->i_width;
- p_enc->fmt_in.video.i_visible_height = fmt_out->i_height;
- }
- }
- else if( fmt_out->i_sar_num && fmt_out->i_sar_den &&
- fmt_out->i_sar_num * fmt_in->i_sar_den !=
- fmt_out->i_sar_den * fmt_in->i_sar_num )
- {
- p_enc->fmt_in.video.i_width =
- fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den * fmt_in->i_width /
- fmt_in->i_sar_den / fmt_out->i_sar_num;
- p_enc->fmt_in.video.i_visible_width =
- fmt_in->i_sar_num * (int64_t)fmt_out->i_sar_den *
- fmt_in->i_visible_width / fmt_in->i_sar_den / fmt_out->i_sar_num;
- }
-
- p_enc->fmt_in.video.i_frame_rate = 25;
- p_enc->fmt_in.video.i_frame_rate_base = 1;
-
- es_format_Init( &p_enc->fmt_out, VIDEO_ES, fmt_out->i_chroma );
- p_enc->fmt_out.video = *fmt_out;
- p_enc->fmt_out.video.i_width = p_enc->fmt_in.video.i_width;
- p_enc->fmt_out.video.i_height = p_enc->fmt_in.video.i_height;
-
- /* Find a suitable decoder module */
- p_enc->p_module = module_need( p_enc, "encoder", NULL, false );
- if( !p_enc->p_module )
- {
- msg_Err( p_enc, "no suitable encoder module for fourcc `%4.4s'.\n"
- "VLC probably does not support this image format.",
- (char*)&p_enc->fmt_out.i_codec );
-
- DeleteEncoder( p_enc );
- return NULL;
- }
- p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec;
-
- return p_enc;
-}
-
-static void DeleteEncoder( encoder_t * p_enc )
-{
- if( p_enc->p_module ) module_unneed( p_enc, p_enc->p_module );
-
- es_format_Clean( &p_enc->fmt_in );
- es_format_Clean( &p_enc->fmt_out );
-
- vlc_object_release( p_enc );
- p_enc = NULL;
-}
-
-static filter_t *CreateFilter( vlc_object_t *p_this, es_format_t *p_fmt_in,
- video_format_t *p_fmt_out,
- const char *psz_module )
-{
- filter_t *p_filter;
-
- p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" );
- p_filter->pf_video_buffer_new =
- (picture_t *(*)(filter_t *))video_new_buffer;
- p_filter->pf_video_buffer_del =
- (void (*)(filter_t *, picture_t *))video_del_buffer;
-
- p_filter->fmt_in = *p_fmt_in;
- p_filter->fmt_out = *p_fmt_in;
- p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
- p_filter->fmt_out.video = *p_fmt_out;
- p_filter->p_module = module_need( p_filter, "video filter2",
- psz_module, false );
-
- if( !p_filter->p_module )
- {
- msg_Dbg( p_filter, "no video filter found" );
- DeleteFilter( p_filter );
- return NULL;
- }
-
- return p_filter;
-}
-
-static void DeleteFilter( filter_t * p_filter )
-{
- if( p_filter->p_module ) module_unneed( p_filter, p_filter->p_module );
-
- es_format_Clean( &p_filter->fmt_in );
- es_format_Clean( &p_filter->fmt_out );
-
- vlc_object_release( p_filter );
-}
--
1.7.9.5
More information about the vlc-devel
mailing list