summaryrefslogtreecommitdiff
path: root/src/libxinevdec/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libxinevdec/image.c')
-rw-r--r--src/libxinevdec/image.c423
1 files changed, 423 insertions, 0 deletions
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 <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <png.h>
+
+#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; i<this->height; 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<<SCALEBITS) + 0.5 ) )
+#define ONE_HALF ( (int32_t) (1<< (SCALEBITS-1)) )
+#define CBCR_OFFSET (CENTERSAMPLE << SCALEBITS)
+
+void end_callback(png_structp png_ptr, png_infop info) {
+
+ vo_frame_t *img; /* video out frame */
+ int row, col;
+
+ /*
+ * libpng has read end of image, now convert rows into a video frame
+ */
+
+ image_decoder_t *this = png_get_progressive_ptr(png_ptr);
+#ifdef LOG
+ printf("image: png end cb\n");
+#endif
+
+ if (this->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; row<this->height; row++) {
+
+ uint16_t *out;
+
+ out = (uint16_t *) (img->base[0] + row * img->pitches[0] );
+
+ for (col=0; col<this->width; 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 }
+};