From a3d1eac9b0f3acac4a0bea2e31b2a26be7ae8c2f Mon Sep 17 00:00:00 2001 From: Stefan Holst Date: Sun, 23 Mar 2003 17:12:26 +0000 Subject: png image support CVS patchset: 4472 CVS date: 2003/03/23 17:12:26 --- src/demuxers/Makefile.am | 9 +- src/demuxers/demux_image.c | 278 +++++++++++++++++++++++++++ src/libxinevdec/Makefile.am | 11 +- src/libxinevdec/image.c | 423 +++++++++++++++++++++++++++++++++++++++++ src/xine-engine/buffer.h | 3 +- src/xine-engine/buffer_types.c | 11 +- 6 files changed, 731 insertions(+), 4 deletions(-) create mode 100644 src/demuxers/demux_image.c create mode 100644 src/libxinevdec/image.c (limited to 'src') diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index 27cf845ae..c709b8734 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -18,6 +18,10 @@ if HAVE_LIBMNG mng_module = xineplug_dmx_mng.la endif +if HAVE_LIBPNG +image_module = xineplug_dmx_image.la +endif + ## # IMPORTANT: # --------- @@ -25,7 +29,7 @@ endif XINELIB = $(top_builddir)/src/xine-engine/libxine.la -lib_LTLIBRARIES = $(ogg_module) $(asf_module) $(mng_module) \ +lib_LTLIBRARIES = $(ogg_module) $(asf_module) $(mng_module) $(image_module) \ xineplug_dmx_games.la \ xineplug_dmx_audio.la \ xineplug_dmx_mpeg_ts.la \ @@ -121,6 +125,9 @@ xineplug_dmx_yuv_frames_la_SOURCES = demux_yuv_frames.c xineplug_dmx_yuv_frames_la_LIBADD = $(XINELIB) xineplug_dmx_yuv_frames_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ +xineplug_dmx_image_la_SOURCES = demux_image.c +xineplug_dmx_image_la_LIBADD = $(XINELIB) +xineplug_dmx_image_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ include_HEADERS = demux.h noinst_HEADERS = asfheader.h qtpalette.h diff --git a/src/demuxers/demux_image.c b/src/demuxers/demux_image.c new file mode 100644 index 000000000..cb4ade795 --- /dev/null +++ b/src/demuxers/demux_image.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: demux_image.c,v 1.1 2003/03/23 17:12:29 holstsn Exp $ + * + * image dummy demultiplexer + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "xine_internal.h" +#include "xineutils.h" +#include "demux.h" + + +/* +#define LOG +*/ + +typedef struct demux_image_s { + demux_plugin_t demux_plugin; + + xine_stream_t *stream; + + fifo_buffer_t *video_fifo; + + input_plugin_t *input; + + int status; + +} demux_image_t ; + +typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + config_values_t *config; + +} demux_image_class_t; + + +static int demux_image_get_status (demux_plugin_t *this_gen) { + demux_image_t *this = (demux_image_t *) this_gen; + + return this->status; +} + +static int demux_image_send_chunk (demux_plugin_t *this_gen) { + demux_image_t *this = (demux_image_t *) this_gen; + buf_element_t *buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + buf->content = buf->mem; + buf->type = BUF_VIDEO_IMAGE; + + buf->size = this->input->read (this->input, buf->mem, buf->max_size-1); + + if (buf->size <= 0) { + buf->free_buffer(buf); + this->status = DEMUX_FINISHED; + } else { + +#ifdef LOG + printf("demux_image: got %i bytes\n", buf->size); +#endif + + this->video_fifo->put (this->video_fifo, buf); + this->status = DEMUX_OK; + } + return this->status; +} + +static void demux_image_send_headers (demux_plugin_t *this_gen) { + + demux_image_t *this = (demux_image_t *) this_gen; + + this->video_fifo = this->stream->video_fifo; + + this->status = DEMUX_OK; + + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 0; + + this->input->seek (this->input, 0, SEEK_SET); +} + +static int demux_image_seek (demux_plugin_t *this_gen, + off_t start_pos, int start_time) { + + demux_image_t *this = (demux_image_t *) this_gen; + + return this->status; +} + +static int demux_image_get_stream_length (demux_plugin_t *this_gen) { + + /* demux_image_t *this = (demux_image_t *) this_gen; */ + + return 0; +} + +static uint32_t demux_image_get_capabilities(demux_plugin_t *this_gen) { + return DEMUX_CAP_NOCAP; +} + +static int demux_image_get_optional_data(demux_plugin_t *this_gen, + void *data, int data_type) { + return DEMUX_OPTIONAL_UNSUPPORTED; +} + +static void demux_image_dispose (demux_plugin_t *this_gen) { + + demux_image_t *this = (demux_image_t *) this_gen; + +#ifdef LOG + printf("demux_image: closed\n"); +#endif + + free (this); +} + +static demux_plugin_t *open_plugin (demux_class_t *class_gen, + xine_stream_t *stream, + input_plugin_t *input) { + + demux_image_t *this; + + switch (stream->content_detection_method) { + + case METHOD_BY_CONTENT: + return NULL; + break; + + case METHOD_BY_EXTENSION: { + + char *ending, *mrl; + + mrl = input->get_mrl (input); + + ending = strrchr(mrl, '.'); + + if (!ending) { + return NULL; + } + + if (strncasecmp (ending, ".png", 4)) { + return NULL; + } + } + break; + + case METHOD_EXPLICIT: + break; + + default: + return NULL; + } +#ifdef LOG + printf ("demux_image: input accepted.\n"); +#endif + /* + * if we reach this point, the input has been accepted. + */ + + this = xine_xmalloc (sizeof (demux_image_t)); + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = demux_image_send_headers; + this->demux_plugin.send_chunk = demux_image_send_chunk; + this->demux_plugin.seek = demux_image_seek; + this->demux_plugin.dispose = demux_image_dispose; + this->demux_plugin.get_status = demux_image_get_status; + this->demux_plugin.get_stream_length = demux_image_get_stream_length; + this->demux_plugin.get_video_frame = NULL; + this->demux_plugin.got_video_frame_cb= NULL; + this->demux_plugin.get_capabilities = demux_image_get_capabilities; + this->demux_plugin.get_optional_data = demux_image_get_optional_data; + this->demux_plugin.demux_class = class_gen; + + this->status = DEMUX_FINISHED; + +#ifdef LOG + printf("demux_image: opened\n"); +#endif + + return &this->demux_plugin; +} + +/* + * image demuxer class + */ + +static char *get_description (demux_class_t *this_gen) { + return "image demux plugin"; +} + +static char *get_identifier (demux_class_t *this_gen) { + return "imagedmx"; +} + +static char *get_extensions (demux_class_t *this_gen) { + return "png"; +} + +static char *get_mimetypes (demux_class_t *this_gen) { + return NULL; +} + +static void class_dispose (demux_class_t *this_gen) { + + demux_image_class_t *this = (demux_image_class_t *) this_gen; + +#ifdef LOG + printf("demux_image: class closed\n"); +#endif + + free (this); +} + +static void *init_class (xine_t *xine, void *data) { + + demux_image_class_t *this; + + this = xine_xmalloc (sizeof (demux_image_class_t)); + this->config = xine->config; + this->xine = xine; + + this->demux_class.open_plugin = open_plugin; + this->demux_class.get_description = get_description; + this->demux_class.get_identifier = get_identifier; + this->demux_class.get_mimetypes = get_mimetypes; + this->demux_class.get_extensions = get_extensions; + this->demux_class.dispose = class_dispose; + +#ifdef LOG + printf("demux_image: class opened\n"); +#endif + + return this; +} + +/* + * exported plugin catalog entry + */ + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 20, "image", XINE_VERSION_CODE, NULL, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/libxinevdec/Makefile.am b/src/libxinevdec/Makefile.am index 5e6e2e256..3598a0145 100644 --- a/src/libxinevdec/Makefile.am +++ b/src/libxinevdec/Makefile.am @@ -2,9 +2,14 @@ EXTRA_DIST = foovideo.c LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic +if HAVE_LIBPNG +image_module = xineplug_decode_image.la +endif + libdir = $(XINE_PLUGINDIR) XINE_LIB = $(top_builddir)/src/xine-engine/libxine.la -lib_LTLIBRARIES = \ + +lib_LTLIBRARIES = $(image_module) \ xineplug_decode_cinepak.la \ xineplug_decode_cyuv.la \ xineplug_decode_fli.la \ @@ -86,6 +91,10 @@ xineplug_decode_yuv_frames_la_SOURCES = yuv_frames.c xineplug_decode_yuv_frames_la_LIBADD = $(XINE_LIB) xineplug_decode_yuv_frames_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ +xineplug_decode_image_la_SOURCES = image.c +xineplug_decode_image_la_LIBADD = $(XINE_LIB) $(DYNAMIC_LD_LIBS) $(PNG_LIBS) +xineplug_decode_image_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + noinst_HEADERS = svq1_codebooks.h $(XINE_LIB): diff --git a/src/libxinevdec/image.c b/src/libxinevdec/image.c new file mode 100644 index 000000000..6e085d8f1 --- /dev/null +++ b/src/libxinevdec/image.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: image.c,v 1.1 2003/03/23 17:12:30 holstsn Exp $ + * + * a image video decoder + */ + + +#include +#include +#include +#include +#include +#include + +#include + +#include "xine_internal.h" +#include "video_out.h" +#include "buffer.h" + +/* +#define LOG +*/ + +typedef struct { + video_decoder_class_t decoder_class; + + /* + * private variables + */ + +} image_class_t; + + +typedef struct image_decoder_s { + video_decoder_t video_decoder; + + image_class_t *cls; + + xine_stream_t *stream; + int video_open; + int pts; + + /* png */ + png_structp png_ptr; + png_infop info_ptr; + char *user_error_ptr; + png_uint_32 width, height; + int bit_depth, + color_type, + interlace_type, + compression_type, + filter_type; + png_bytep *rows; + jmp_buf jmpbuf; + int passes, rowbytes; + int rows_valid; + +} image_decoder_t; + +/* + * png stuff + */ + +void info_callback(png_structp png_ptr, png_infop info); +void row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass); +void end_callback(png_structp png_ptr, png_infop info); + +int initialize_png_reader(image_decoder_t *this) { + + this->png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)this, + NULL, NULL); + if (!this->png_ptr) + return -1; + + this->info_ptr = png_create_info_struct(this->png_ptr); + + if (!this->info_ptr) { + png_destroy_read_struct(&this->png_ptr, NULL, NULL); + return -1; + } + + if (setjmp(this->jmpbuf)) { + png_destroy_read_struct(&this->png_ptr, &this->info_ptr, + (png_infopp)NULL); + return -1; + } + + png_set_progressive_read_fn(this->png_ptr, (void *)this, + info_callback, row_callback, end_callback); + + return 0; +} + +int process_data(image_decoder_t *this, png_bytep buffer, png_uint_32 length) { + + if (setjmp(this->jmpbuf)) { + png_destroy_read_struct(&this->png_ptr, &this->info_ptr, (png_infopp)NULL); + return -1; + } + png_process_data(this->png_ptr, this->info_ptr, buffer, length); + return 0; +} + + /* + * process png header (do some conversions if necessary) + */ + +void info_callback(png_structp png_ptr, png_infop info_ptr) { + int i; + image_decoder_t *this = png_get_progressive_ptr(png_ptr); + +#ifdef LOG + printf("image: png info cb\n"); +#endif + png_get_IHDR(png_ptr, info_ptr, &this->width, &this->height, + &this->bit_depth, &this->color_type, &this->interlace_type, + &this->compression_type, &this->filter_type); + + + /* expand palette images to RGB, low-bit-depth + * grayscale images to 8 bits, transparency chunks to full alpha channel; + * strip 16-bit-per-sample images to 8 bits per sample; and convert + * grayscale to RGB[A] */ + + if (this->color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (this->color_type == PNG_COLOR_TYPE_GRAY && this->bit_depth < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (this->bit_depth == 16) + png_set_strip_16(png_ptr); + if (this->color_type == PNG_COLOR_TYPE_GRAY || + this->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + + /* we'll let libpng expand interlaced images, too */ + + this->passes = png_set_interlace_handling(png_ptr); + + /* all transformations have been registered; now update info_ptr data and + * then get rowbytes */ + + png_read_update_info(png_ptr, info_ptr); + + this->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); + + this->rows = xine_xmalloc(sizeof(png_bytep)*this->height); + + for (i=0; iheight; i++) { + this->rows[i] = xine_xmalloc(this->rowbytes); + } + this->rows_valid = 1; +} + +void row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) { + + image_decoder_t *this = png_get_progressive_ptr(png_ptr); + + if (!new_row) return; + + /* + * copy new row to this->rows + */ + + png_progressive_combine_row(png_ptr, this->rows[row_num], new_row); +} + +/* for rgb2yuv */ +#define CENTERSAMPLE 128 +#define SCALEBITS 16 +#define FIX(x) ( (int32_t) ( (x) * (1<rows_valid) { + img = this->stream->video_out->get_frame (this->stream->video_out, this->width, + this->height, XINE_VO_ASPECT_DONT_TOUCH, + XINE_IMGFMT_YUY2, + VO_BOTH_FIELDS); + + img->pts = this->pts; + img->duration = 3600; + img->bad_frame = 0; + + for (row=0; rowheight; row++) { + + uint16_t *out; + + out = (uint16_t *) (img->base[0] + row * img->pitches[0] ); + + for (col=0; colwidth; col++, out++) { + + uint8_t r,g,b; + uint8_t y,u,v; + + r = *(this->rows[row]+col*3); + g = *(this->rows[row]+col*3+1); + b = *(this->rows[row]+col*3+2); + y = (FIX(0.299) * r + FIX(0.587) * g + FIX(0.114) * b + ONE_HALF) + >> SCALEBITS; + if (!(col & 0x0001)) { + /* even pixel, do u */ + u = (- FIX(0.16874) * r - FIX(0.33126) * g + FIX(0.5) * b + + CBCR_OFFSET + ONE_HALF-1) >> SCALEBITS; + *out = ( (uint16_t) u << 8) | (uint16_t) y; + } else { + /* odd pixel, do v */ + v = (FIX(0.5) * r - FIX(0.41869) * g - FIX(0.08131) * b + + CBCR_OFFSET + ONE_HALF-1) >> SCALEBITS; + *out = ( (uint16_t) v << 8) | (uint16_t) y; + } + } + } + this->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = img->duration; + img->draw(img, this->stream); + img->free(img); + } +} + + +/* + * png stuff end + */ + +static void image_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { + image_decoder_t *this = (image_decoder_t *) this_gen; + + if (!this->video_open) { +#ifdef LOG + printf("image: opening video\n"); +#endif + this->stream->video_out->open(this->stream->video_out, this->stream); + this->video_open = 1; + } +#ifdef LOG + printf("image: have to decode data\n"); +#endif + + this->pts = buf->pts; + if (process_data(this, buf->content, buf->size) < 0) + { + printf("image: error processing data\n"); + } +} + + +static void image_flush (video_decoder_t *this_gen) { + /* image_decoder_t *this = (image_decoder_t *) this_gen; */ + + /* + * flush out any frames that are still stored in the decoder + */ +} + + +static void image_reset (video_decoder_t *this_gen) { + /* image_decoder_t *this = (image_decoder_t *) this_gen; */ + + /* + * reset decoder after engine flush (prepare for new + * video data not related to recently decoded data) + */ +} + + +static void image_discontinuity (video_decoder_t *this_gen) { + /* image_decoder_t *this = (image_decoder_t *) this_gen; */ + + /* + * a time reference discontinuity has happened. + * that is, it must forget any currently held pts value + */ +} + +static void image_dispose (video_decoder_t *this_gen) { + image_decoder_t *this = (image_decoder_t *) this_gen; + + if (this->video_open) { +#ifdef LOG + printf("image: closing video\n"); +#endif + this->stream->video_out->close(this->stream->video_out, this->stream); + this->video_open = 0; + } + +#ifdef LOG + printf("image: closed\n"); +#endif + free (this); +} + + +static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, + xine_stream_t *stream) { + + image_class_t *cls = (image_class_t *) class_gen; + image_decoder_t *this; + +#ifdef LOG + printf("image: opened\n"); +#endif + + this = (image_decoder_t *) xine_xmalloc (sizeof (image_decoder_t)); + + this->video_decoder.decode_data = image_decode_data; + this->video_decoder.flush = image_flush; + this->video_decoder.reset = image_reset; + this->video_decoder.discontinuity = image_discontinuity; + this->video_decoder.dispose = image_dispose; + this->cls = cls; + this->stream = stream; + + /* + * initialisation of privates + */ + + if (initialize_png_reader(this) < 0) { + printf("image: failed to init png reader\n"); + } + + return &this->video_decoder; +} + +/* + * image plugin class + */ + +static char *get_identifier (video_decoder_class_t *this) { + return "imagevdec"; +} + +static char *get_description (video_decoder_class_t *this) { + return "image video decoder plugin"; +} + +static void dispose_class (video_decoder_class_t *this_gen) { + image_class_t *this = (image_class_t *) this_gen; + +#ifdef LOG + printf("image: class closed\n"); +#endif + + free (this); +} + +static void *init_class (xine_t *xine, void *data) { + + image_class_t *this; + /* config_values_t *config = xine->config; */ + + this = (image_class_t *) xine_xmalloc (sizeof (image_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + /* + * initialisation of privates + */ + +#ifdef LOG + printf("image: class opened\n"); +#endif + + return this; +} + +/* + * exported plugin catalog entry + */ + +static uint32_t supported_types[] = { BUF_VIDEO_IMAGE, + 0 }; + +static decoder_info_t dec_info_image = { + supported_types, /* supported types */ + 6 /* priority */ +}; + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_DECODER, 14, "image", XINE_VERSION_CODE, &dec_info_image, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index 3f0335297..a1d9073df 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer.h,v 1.104 2003/03/18 20:41:02 jstembridge Exp $ + * $Id: buffer.h,v 1.105 2003/03/23 17:12:30 holstsn Exp $ * * * contents: @@ -143,6 +143,7 @@ extern "C" { #define BUF_VIDEO_PSX_MDEC 0x023A0000 #define BUF_VIDEO_YUV_FRAMES 0x023B0000 /* uncompressed YUV, delivered by v4l input plugin */ #define BUF_VIDEO_HUFFYUV 0x023C0000 +#define BUF_VIDEO_IMAGE 0x023D0000 /* audio buffer types: (please keep in sync with buffer_types.c) */ diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index d7091917e..f144e732b 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer_types.c,v 1.55 2003/03/18 20:41:03 jstembridge Exp $ + * $Id: buffer_types.c,v 1.56 2003/03/23 17:12:30 holstsn Exp $ * * * contents: @@ -534,6 +534,15 @@ static video_db_t video_db[] = { BUF_VIDEO_HUFFYUV, "HuffYUV" }, +{ + { + meFOURCC('I', 'M', 'G', ' '), + 0, + }, + BUF_VIDEO_IMAGE, + "Image" +}, + { { 0 }, 0, "last entry" } }; -- cgit v1.2.3