diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/demuxers/demux_real.c | 500 | ||||
-rw-r--r-- | src/libreal/Makefile.am | 29 | ||||
-rw-r--r-- | src/libreal/xine_decoder.c | 386 | ||||
-rw-r--r-- | src/xine-engine/buffer.h | 9 |
6 files changed, 813 insertions, 115 deletions
diff --git a/configure.ac b/configure.ac index 615fb020f..62ee70e96 100644 --- a/configure.ac +++ b/configure.ac @@ -1153,6 +1153,7 @@ src/libw32dll/DirectShow/Makefile src/libxinevdec/Makefile src/libxineadec/Makefile src/libxineadec/gsm610/Makefile +src/libreal/Makefile src/video_out/Makefile src/video_out/libdha/Makefile src/video_out/libdha/bin/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 6d887a28b..4d9c4aec1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,8 @@ SUBDIRS = \ liblpcm \ libxinevdec \ libxineadec \ - libvorbis + libvorbis \ + libreal debug: @list='$(SUBDIRS)'; for subdir in $$list; do \ diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index 141a07467..c8df16963 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -21,7 +21,7 @@ * For more information regarding the Real file format, visit: * http://www.pcisys.net/~melanson/codecs/ * - * $Id: demux_real.c,v 1.8 2002/11/09 23:22:32 guenter Exp $ + * $Id: demux_real.c,v 1.9 2002/11/18 03:03:09 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -40,6 +40,8 @@ #include "demux.h" #include "bswap.h" +#define LOG + #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ ( (long)(unsigned char)(ch3) | \ ( (long)(unsigned char)(ch2) << 8 ) | \ @@ -60,15 +62,23 @@ #define PN_KEYFRAME_FLAG 0x0002 +#define MAX_STREAMS 10 + typedef struct { - int stream; - int64_t offset; - unsigned int size; - int64_t pts; - int keyframe; + int stream; + int64_t offset; + unsigned int size; + int64_t pts; + int keyframe; } real_packet; typedef struct { + int num; + int32_t buf_type ; + fifo_buffer_t *fifo; +} stream_info_t; + +typedef struct { demux_plugin_t demux_plugin; @@ -85,6 +95,8 @@ typedef struct { off_t data_size; int status; unsigned int duration; + int packet_count; + int bitrate; unsigned int video_type; unsigned int audio_type; @@ -95,9 +107,8 @@ typedef struct { unsigned int audio_sample_rate; unsigned int audio_bits; - unsigned int packet_count; - unsigned int current_packet; - real_packet *packets; + int num_streams; + stream_info_t streams[MAX_STREAMS]; unsigned int current_data_chunk_packet_count; unsigned int next_data_chunk_offset; @@ -115,30 +126,178 @@ typedef struct { config_values_t *config; } demux_real_class_t; -/* returns 1 if the real file was opened successfully, 0 otherwise */ -static int open_real_file(demux_real_t *this) { +typedef struct { + + u_int16_t object_version; + + u_int16_t stream_number; + u_int32_t max_bit_rate; + u_int32_t avg_bit_rate; + u_int32_t max_packet_size; + u_int32_t avg_packet_size; + u_int32_t start_time; + u_int32_t preroll; + u_int32_t duration; + char stream_name_size; + char *stream_name; + char mime_type_size; + char *mime_type; + u_int32_t type_specific_len; + char *type_specific_data; + +} pnm_mdpr_t; + +void hexdump (char *buf, int length) { + + int i; + + printf ("pnm: ascii contents>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + printf ("%c", c); + else + printf ("."); + } + printf ("\n"); + + printf ("pnm: complete hexdump of package follows:\npnm: "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\npnm: "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} + +static pnm_mdpr_t *pnm_parse_mdpr(const char *data) { + + pnm_mdpr_t *mdpr=malloc(sizeof(pnm_mdpr_t)); + + mdpr->object_version=BE_16(&data[0]); + + if (mdpr->object_version != 0) { + printf("warning: unknown object version in MDPR: 0x%04x\n", + mdpr->object_version); + } + + mdpr->stream_number=BE_16(&data[2]); + mdpr->max_bit_rate=BE_32(&data[4]); + mdpr->avg_bit_rate=BE_32(&data[8]); + mdpr->max_packet_size=BE_32(&data[12]); + mdpr->avg_packet_size=BE_32(&data[16]); + mdpr->start_time=BE_32(&data[20]); + mdpr->preroll=BE_32(&data[24]); + mdpr->duration=BE_32(&data[28]); + + mdpr->stream_name_size=data[32]; + mdpr->stream_name=malloc(sizeof(char)*(mdpr->stream_name_size+1)); + memcpy(mdpr->stream_name, &data[33], mdpr->stream_name_size); + mdpr->stream_name[mdpr->stream_name_size]=0; + + mdpr->mime_type_size=data[33+mdpr->stream_name_size]; + mdpr->mime_type=malloc(sizeof(char)*(mdpr->mime_type_size+1)); + memcpy(mdpr->mime_type, &data[34+mdpr->stream_name_size], mdpr->mime_type_size); + mdpr->mime_type[mdpr->mime_type_size]=0; + + mdpr->type_specific_len=BE_32(&data[34+mdpr->stream_name_size+mdpr->mime_type_size]); + mdpr->type_specific_data=malloc(sizeof(char)*(mdpr->type_specific_len)); + memcpy(mdpr->type_specific_data, + &data[38+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len); + + printf("pnm: MDPR: stream number: %i\n", mdpr->stream_number); + printf("pnm: MDPR: maximal bit rate: %i\n", mdpr->max_bit_rate); + printf("pnm: MDPR: average bit rate: %i\n", mdpr->avg_bit_rate); + printf("pnm: MDPR: largest packet size: %i bytes\n", mdpr->max_packet_size); + printf("pnm: MDPR: average packet size: %i bytes\n", mdpr->avg_packet_size); + printf("pnm: MDPR: start time: %i\n", mdpr->start_time); + printf("pnm: MDPR: pre-buffer: %i ms\n", mdpr->preroll); + printf("pnm: MDPR: duration of stream: %i ms\n", mdpr->duration); + printf("pnm: MDPR: stream name: %s\n", mdpr->stream_name); + printf("pnm: MDPR: mime type: %s\n", mdpr->mime_type); + printf("pnm: MDPR: type specific data:\n"); + hexdump(mdpr->type_specific_data, mdpr->type_specific_len); + printf("\n"); + + return mdpr; +} + +typedef struct dp_hdr_s { + uint32_t chunks; /* number of chunks */ + uint32_t timestamp; /* timestamp from packet header */ + uint32_t len; /* length of actual data */ + uint32_t chunktab; /* offset to chunk offset array */ +} dp_hdr_t; + +static void send_real_buf (demux_real_t *this, uint32_t timestamp, int len, + fifo_buffer_t *fifo, + uint32_t buf_type, uint32_t decoder_flags) { + + dp_hdr_t *hdr; + buf_element_t *buf; + + if (!fifo) { + this->input->seek (this->input, len, SEEK_CUR); + return; + } + + buf = fifo->buffer_pool_alloc (fifo); + + buf->content = buf->mem; + + hdr = buf->content; + hdr->chunks = 1; + hdr->timestamp = timestamp; + hdr->len = len; + hdr->chunktab = 0; + + this->input->read (this->input, buf->content+16, len); + + buf->size = len+16; + + buf->input_pos = 0 ; /* FIXME */ + buf->input_time = 0 ; /* FIXME */ + buf->type = buf_type; + buf->decoder_flags = decoder_flags; + + fifo->put (fifo, buf); + +} + + +static void real_parse_headers (demux_real_t *this) { - char preamble[PREAMBLE_SIZE]; - unsigned int chunk_type = 0; - unsigned int chunk_size; + char preamble[PREAMBLE_SIZE]; + unsigned int chunk_type = 0; + unsigned int chunk_size; unsigned char *chunk_buffer; - int field_size; - int stream_ptr; - unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; - unsigned char signature[REAL_SIGNATURE_SIZE]; + int field_size; + int stream_ptr; + unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; + unsigned char signature[REAL_SIGNATURE_SIZE]; this->data_start = 0; this->data_size = 0; - this->packets = NULL; - this->current_packet = 0; this->input->seek(this->input, 0, SEEK_SET); if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) != - REAL_SIGNATURE_SIZE) - return 0; + REAL_SIGNATURE_SIZE) { + this->status = DEMUX_FINISHED; + return; + } - if (BE_32(signature) != RMF_TAG) - return 0; + if (BE_32(signature) != RMF_TAG) { + this->status = DEMUX_FINISHED; + return; + } /* skip to the start of the first chunk (the first chunk is 0x12 bytes * long) and start traversing */ @@ -149,8 +308,10 @@ static int open_real_file(demux_real_t *this) { while (chunk_type != DATA_TAG) { if (this->input->read(this->input, preamble, PREAMBLE_SIZE) != - PREAMBLE_SIZE) - return 0; + PREAMBLE_SIZE) { + this->status = DEMUX_FINISHED; + return; + } chunk_type = BE_32(&preamble[0]); chunk_size = BE_32(&preamble[4]); @@ -163,9 +324,9 @@ static int open_real_file(demux_real_t *this) { chunk_size -= PREAMBLE_SIZE; chunk_buffer = xine_xmalloc(chunk_size); if (this->input->read(this->input, chunk_buffer, chunk_size) != - chunk_size) { - free(chunk_buffer); - return 0; + chunk_size) { + this->status = DEMUX_FINISHED; + return; } if (chunk_type == PROP_TAG) { @@ -176,6 +337,91 @@ static int open_real_file(demux_real_t *this) { } else if (chunk_type == MDPR_TAG) { + pnm_mdpr_t *mdpr; + + mdpr = pnm_parse_mdpr (chunk_buffer); + + this->bitrate = mdpr->avg_bit_rate; + this->stream->stream_info[XINE_STREAM_INFO_BITRATE] = mdpr->avg_bit_rate; + + /* detect streamtype */ + + this->streams[this->num_streams].num = mdpr->stream_number; + + if (!strncmp (mdpr->type_specific_data+4, "VIDORV20", 8)) { + + buf_element_t *buf; + + this->streams[this->num_streams].buf_type = BUF_VIDEO_RV20; + this->streams[this->num_streams].fifo = this->video_fifo; + + printf ("demux_real: RV20 video detected\n"); + + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + buf->content = buf->mem; + + memcpy (buf->content, mdpr->type_specific_data, + mdpr->type_specific_len); + + buf->size = mdpr->type_specific_len; + + buf->input_pos = 0 ; + buf->input_time = 0 ; + buf->type = BUF_VIDEO_RV20; + buf->decoder_flags = BUF_FLAG_HEADER; + + this->video_fifo->put (this->video_fifo, buf); + + } else if (!strncmp (mdpr->type_specific_data+4, "VIDORV30", 8)) { + + buf_element_t *buf; + + this->streams[this->num_streams].buf_type = BUF_VIDEO_RV30; + this->streams[this->num_streams].fifo = this->video_fifo; + + printf ("demux_real: RV30 video detected\n"); + + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + buf->content = buf->mem; + + memcpy (buf->content, mdpr->type_specific_data, + mdpr->type_specific_len); + + buf->size = mdpr->type_specific_len; + + buf->input_pos = 0 ; + buf->input_time = 0 ; + buf->type = BUF_VIDEO_RV30; + buf->decoder_flags = BUF_FLAG_HEADER; + + this->video_fifo->put (this->video_fifo, buf); + + } else if ((mdpr->type_specific_len>61) + && (!strncmp (mdpr->type_specific_data+57, "sipr", 4))) { + + this->streams[this->num_streams].buf_type = BUF_AUDIO_SIPRO; + this->streams[this->num_streams].fifo = this->audio_fifo; + + printf ("demux_real: sipro audio detected\n"); + + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; + + } else { + + printf ("demux_real: codec not recognized\n"); + + this->streams[this->num_streams].buf_type = 0; + this->streams[this->num_streams].fifo = NULL; + } + + this->num_streams++; + free (mdpr); } else if (chunk_type == CONT_TAG) { @@ -227,8 +473,11 @@ static int open_real_file(demux_real_t *this) { case DATA_TAG: if (this->input->read(this->input, data_chunk_header, - DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE) - return 0; + DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE) { + this->status = DEMUX_FINISHED; + return ; + } + this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]); this->next_data_chunk_offset = BE_32(&data_chunk_header[6]); break; @@ -240,54 +489,59 @@ static int open_real_file(demux_real_t *this) { } } - - /* allocate space for the packet list */ - this->packets = xine_xmalloc(this->packet_count * sizeof(real_packet)); - - return 1; } static int demux_real_send_chunk(demux_plugin_t *this_gen) { - demux_real_t *this = (demux_real_t *) this_gen; - buf_element_t *buf = NULL; - char preamble[PREAMBLE_SIZE]; - unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; - char header[DATA_PACKET_HEADER_SIZE]; + demux_real_t *this = (demux_real_t *) this_gen; + char preamble[PREAMBLE_SIZE]; + unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; + char header[DATA_PACKET_HEADER_SIZE]; + int stream_num,i; + int stream, size, keyframe; + uint32_t timestamp; + int64_t pts; + off_t offset; /* load a header from wherever the stream happens to be pointing */ if (this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE) != - DATA_PACKET_HEADER_SIZE) { + DATA_PACKET_HEADER_SIZE) { this->status = DEMUX_FINISHED; return this->status; } - /* log the packet information */ - this->packets[this->current_packet].stream = BE_16(&header[4]); - this->packets[this->current_packet].offset = - this->input->get_current_pos(this->input); - this->packets[this->current_packet].size = - BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; - this->packets[this->current_packet].pts = - BE_32(&header[6]); - this->packets[this->current_packet].pts *= 90; - this->packets[this->current_packet].keyframe = - (header[11] & PN_KEYFRAME_FLAG); + /* read the packet information */ + stream = BE_16(&header[4]); + offset = this->input->get_current_pos(this->input); + size = BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; + timestamp= BE_32(&header[6]); + pts = (int64_t) timestamp * 90; + keyframe = header[11] & PN_KEYFRAME_FLAG; + +#ifdef LOG + printf ("demux_real: packet of stream %d, 0x%X bytes @ %llX, pts = %lld%s\n", + stream, size, offset, pts, keyframe ? ", keyframe" : ""); +#endif + + stream_num = -1; -printf ("packet %d: stream %d, 0x%X bytes @ %llX, pts = %lld%s\n", -this->current_packet, -this->packets[this->current_packet].stream, -this->packets[this->current_packet].size, -this->packets[this->current_packet].offset, -this->packets[this->current_packet].pts, -(this->packets[this->current_packet].keyframe) ? ", keyframe" : ""); + for (i=0; i<this->num_streams; i++) { + + if (this->streams[i].num == stream) + stream_num = i; + } + if (stream_num >= 0) { + printf ("demux_real: buf type is %08x\n", this->streams[stream_num].buf_type); -this->input->seek(this->input, this->packets[this->current_packet].size, -SEEK_CUR); + send_real_buf (this, timestamp, size, + this->streams[stream_num].fifo, + this->streams[stream_num].buf_type, + 0 /* FIXME */); + } else + this->input->seek(this->input, size, SEEK_CUR); - this->current_packet++; this->current_data_chunk_packet_count--; /* check if it's time to reload */ @@ -310,7 +564,9 @@ SEEK_CUR); this->status = DEMUX_FINISHED; return this->status; } -printf ("**** found next DATA tag\n"); +#ifdef LOG + printf ("demux_real: **** found next DATA tag\n"); +#endif this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]); this->next_data_chunk_offset = BE_32(&data_chunk_header[6]); } @@ -325,19 +581,31 @@ printf ("**** found next DATA tag\n"); static void demux_real_send_headers(demux_plugin_t *this_gen) { demux_real_t *this = (demux_real_t *) this_gen; - buf_element_t *buf; this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; this->status = DEMUX_OK; + this->num_streams = 0; + /* send start buffers */ -/* xine_demux_control_start(this->stream); -*/ + xine_demux_control_start(this->stream); /* send init info to decoders */ + this->input->seek (this->input, 0, SEEK_SET); + + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0; + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 0; + real_parse_headers (this); + + + /* print vital stats */ + xine_log (this->stream->xine, XINE_LOG_MSG, + _("demux_real: Real media file, running time: %d min, %d sec\n"), + this->duration / 1000 / 60, + this->duration / 1000 % 60); xine_demux_control_headers_done (this->stream); } @@ -364,7 +632,6 @@ static void demux_real_dispose (demux_plugin_t *this_gen) { demux_real_t *this = (demux_real_t *) this_gen; - free(this->packets); free(this); } @@ -388,36 +655,38 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input = (input_plugin_t *) input_gen; demux_real_t *this; - if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) { - printf(_("demux_real.c: input not seekable, can not handle!\n")); - return NULL; - } - - this = xine_xmalloc (sizeof (demux_real_t)); - this->stream = stream; - this->input = input; - - this->demux_plugin.send_headers = demux_real_send_headers; - this->demux_plugin.send_chunk = demux_real_send_chunk; - this->demux_plugin.seek = demux_real_seek; - this->demux_plugin.dispose = demux_real_dispose; - this->demux_plugin.get_status = demux_real_get_status; - this->demux_plugin.get_stream_length = demux_real_get_stream_length; - this->demux_plugin.get_video_frame = NULL; - this->demux_plugin.got_video_frame_cb= NULL; - this->demux_plugin.demux_class = class_gen; - - this->status = DEMUX_FINISHED; + printf ("demux_real: open_plugin\n"); switch (stream->content_detection_method) { case METHOD_BY_CONTENT: - case METHOD_EXPLICIT: - - if (!open_real_file(this)) { - free (this); - return NULL; + { + uint8_t buf[4096]; + + if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { + + input->seek(input, 0, SEEK_SET); + + if (input->read(input, buf, 4)) { + + if ((buf[0] != 0x2e) + || (buf[1] != 'R') + || (buf[2] != 'M') + || (buf[3] != 'F')) + return NULL; + } + } else if (input->get_optional_data (input, buf, INPUT_OPTIONAL_DATA_PREVIEW)) { + if ((buf[0] != 0x2e) + || (buf[1] != 'R') + || (buf[2] != 'M') + || (buf[3] != 'F')) + return NULL; + } else + return NULL; } + + + printf ("demux_real: by content accepted.\n"); break; @@ -428,37 +697,41 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str ending = strrchr(mrl, '.'); - if (!ending) { - free (this); - return NULL; - } - - if (strncasecmp (ending, ".rm", 3)) { - free (this); + if (!ending) return NULL; - } - if (!open_real_file(this)) { - free (this); + if (strncasecmp (ending, ".rm", 3) + && strncasecmp (ending, ".ra", 3) + && strncasecmp (ending, ".ram", 4)) return NULL; - } } break; + case METHOD_EXPLICIT: + break; + default: - free (this); return NULL; } - strncpy (this->last_mrl, input->get_mrl (input), 1024); - /* print vital stats */ - xine_log (this->stream->xine, XINE_LOG_MSG, - _("demux_real: Real media file, running time: %d min, %d sec\n"), - this->duration / 1000 / 60, - this->duration / 1000 % 60); + this = xine_xmalloc (sizeof (demux_real_t)); + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = demux_real_send_headers; + this->demux_plugin.send_chunk = demux_real_send_chunk; + this->demux_plugin.seek = demux_real_seek; + this->demux_plugin.dispose = demux_real_dispose; + this->demux_plugin.get_status = demux_real_get_status; + this->demux_plugin.get_stream_length = demux_real_get_stream_length; + this->demux_plugin.get_video_frame = NULL; + this->demux_plugin.got_video_frame_cb= NULL; + this->demux_plugin.demux_class = class_gen; + + strncpy (this->last_mrl, input->get_mrl (input), 1024); return &this->demux_plugin; } @@ -472,11 +745,12 @@ static char *get_identifier (demux_class_t *this_gen) { } static char *get_extensions (demux_class_t *this_gen) { - return "rm"; + return "rm ra ram"; } static char *get_mimetypes (demux_class_t *this_gen) { - return NULL; + return "audio/x-pn-realaudio: ra, rm, ram: Real Media File;" + "audio/x-realaudio: ra: Real Media File;"; } static void class_dispose (demux_class_t *this_gen) { diff --git a/src/libreal/Makefile.am b/src/libreal/Makefile.am new file mode 100644 index 000000000..6505cc9c0 --- /dev/null +++ b/src/libreal/Makefile.am @@ -0,0 +1,29 @@ +## +## Process this file with automake to produce Makefile.in +## + +AM_CFLAGS = $(VORBIS_CFLAGS) + +LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic + +libdir = $(XINE_PLUGINDIR) + +lib_LTLIBRARIES = xineplug_decode_real.la + +xineplug_decode_real_la_SOURCES = xine_decoder.c +xineplug_decode_real_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + +debug: +# @$(MAKE) CFLAGS="$(DEBUG_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS)" + @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" + +install-debug: debug + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in diff --git a/src/libreal/xine_decoder.c b/src/libreal/xine_decoder.c new file mode 100644 index 000000000..1912dd974 --- /dev/null +++ b/src/libreal/xine_decoder.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2000-2002 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: xine_decoder.c,v 1.1 2002/11/18 03:03:09 guenter Exp $ + * + * thin layer to use real binary-only codecs in xine + * + * code inspired by work from Florian Schneider for the MPlayer Project + */ + + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <dlfcn.h> + +#include "bswap.h" +#include "xine_internal.h" +#include "video_out.h" +#include "buffer.h" + + +#define LOG + + + +typedef struct { + video_decoder_class_t decoder_class; + void *rv_handle; + + unsigned long (*rvyuv_custom_message)(unsigned long*,void*); + unsigned long (*rvyuv_free)(void*); + unsigned long (*rvyuv_hive_message)(unsigned long,unsigned long); + unsigned long (*rvyuv_init)(void*, void*); /* initdata,context */ + unsigned long (*rvyuv_transform)(char*, char*,unsigned long*,unsigned long*,void*); +} real_class_t; + + +typedef struct realdec_decoder_s { + video_decoder_t video_decoder; + + real_class_t *cls; + + xine_stream_t *stream; + + void *context; + + int width, height; + +} realdec_decoder_t; + +/* we need exact positions */ +typedef struct { + short unk1; + short w; + short h; + short unk3; + int unk2; + int subformat; + int unk5; + int format; +} rv_init_t; + +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 256 + +void hexdump (char *buf, int length) { + + int i; + + printf ("pnm: ascii contents>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + printf ("%c", c); + else + printf ("."); + } + printf ("\n"); + + printf ("pnm: complete hexdump of package follows:\npnm: "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\npnm: "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} + + +typedef struct dp_hdr_s { + uint32_t chunks; /* number of chunks */ + uint32_t timestamp; /* timestamp from packet header */ + uint32_t len; /* length of actual data */ + uint32_t chunktab; /* offset to chunk offset array */ +} dp_hdr_t; + + +static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + real_class_t *cls = this->cls; + +#ifdef LOG + printf ("libreal: decode_data, flags=0x%08x ...\n", buf->decoder_flags); +#endif + + if (buf->decoder_flags & BUF_FLAG_PREVIEW) { + /* real_find_sequence_header (&this->real, buf->content, buf->content + buf->size);*/ + } else if (buf->decoder_flags & BUF_FLAG_HEADER) { + + unsigned int* extrahdr = (unsigned int*) (buf->content+28); + int result; + rv_init_t init_data = {11, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, 0, + 0, 1, 0}; /* rv30 */ + + init_data.w = BE_16(&buf->content[12]); + init_data.h = BE_16(&buf->content[14]); + + init_data.subformat = BE_32(&buf->content[26]); + init_data.format = BE_32(&buf->content[30]); + + hexdump (&init_data, sizeof (init_data)); + + hexdump (buf->content, 32); + hexdump (extrahdr, 10); + + printf ("libreal: init codec %dx%d... %x %x\n", + init_data.w, init_data.h, + init_data.subformat, init_data.format ); + + this->context = NULL; + + result = cls->rvyuv_init (&init_data, &this->context); + + printf ("libreal: ... done %d\n", result); + + /* setup rv30 codec (codec sub-type and image dimensions): */ + if (init_data.format>=0x20200002){ + unsigned long cmsg24[4]={this->width,this->height, + this->width,this->height}; + unsigned long cmsg_data[3]={0x24,1+((init_data.subformat>>16)&7), + (unsigned long) &cmsg24}; + cls->rvyuv_custom_message (cmsg_data, this->context); + + printf ("libreal: special setup for rv30 done\n"); + + } + + /* + real_init (&this->real, stream->video_out); + */ + + this->stream->video_out->open(this->stream->video_out); + + + } else if (this->context) { + + int result; + vo_frame_t *img; + void *data = buf->content; + dp_hdr_t *dp_hdr = (dp_hdr_t*)data; + unsigned char *dp_data = ((unsigned char*)data)+sizeof(dp_hdr_t); + uint32_t *extra = (uint32_t*)(((char*)data)+dp_hdr->chunktab); + unsigned long transform_out[5]; + unsigned long transform_in[6]={ + dp_hdr->len, /* length of the packet (sub-packets appended) */ + 0, /* unknown, seems to be unused */ + dp_hdr->chunks, /* number of sub-packets - 1 */ + (unsigned long) extra, /* table of sub-packet offsets */ + 0, /* unknown, seems to be unused */ + dp_hdr->timestamp /* timestamp (the integer value from the stream) */ + }; + + img = this->stream->video_out->get_frame (this->stream->video_out, + /* this->av_picture.linesize[0], */ + this->width, + this->height, + 42, + XINE_IMGFMT_YV12, + VO_BOTH_FIELDS); + + img->pts = 0; /* FIXME */ + img->duration = 3000; /* FIXME */ + img->bad_frame = 0; + + printf ("libreal: decoding:\n"); + hexdump (data, buf->size); + + result = cls->rvyuv_transform (dp_data, + img->base[0], + transform_in, + transform_out, + this->context); + + /* xine_fast_memcpy (dy, sy, this->bih.biWidth); */ + + img->draw(img); + img->free(img); + + } else { + /* + real_decode_data (&this->real, buf->content, buf->content + buf->size, + buf->pts); + */ + } + +#ifdef LOG + printf ("libreal: decode_data...done\n"); +#endif +} + +static void realdec_flush (video_decoder_t *this_gen) { + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + +#ifdef LOG + printf ("libreal: flush\n"); +#endif + +} + +static void realdec_reset (video_decoder_t *this_gen) { + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + +} + +static void realdec_discontinuity (video_decoder_t *this_gen) { + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + +} + +static void realdec_dispose (video_decoder_t *this_gen) { + + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + +#ifdef LOG + printf ("libreal: close\n"); +#endif + + free (this); +} + +static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, + xine_stream_t *stream) { + + real_class_t *cls = (real_class_t *) class_gen; + realdec_decoder_t *this ; + + this = (realdec_decoder_t *) malloc (sizeof (realdec_decoder_t)); + memset(this, 0, sizeof (realdec_decoder_t)); + + this->video_decoder.decode_data = realdec_decode_data; + this->video_decoder.flush = realdec_flush; + this->video_decoder.reset = realdec_reset; + this->video_decoder.discontinuity = realdec_discontinuity; + this->video_decoder.dispose = realdec_dispose; + this->stream = stream; + this->cls = cls; + + this->context = 0; + + return &this->video_decoder; +} + +/* + * real plugin class + */ + +static char *get_identifier (video_decoder_class_t *this) { + return "realdec"; +} + +static char *get_description (video_decoder_class_t *this) { + return "real binary-only codec based video decoder plugin"; +} + +static void dispose_class (video_decoder_class_t *this) { + free (this); +} + +/* + * some fake functions to make real codecs happy + */ +void *__builtin_vec_new(unsigned long size) { + return malloc(size); +} +void __builtin_vec_delete(void *mem) { + free(mem); +} +void __pure_virtual(void) { + printf("libreal: FATAL: __pure_virtual() called!\n"); + /* exit(1); */ +} + +/* + * real codec loader + */ + +static int load_syms_linux (real_class_t *cls, char *path) { + + printf ("libreal: opening shared obj '%s'\n", path); + cls->rv_handle = dlopen (path, RTLD_LAZY); + + if (!cls->rv_handle) { + printf ("libreal: error: %s\n", dlerror()); + return 0; + } + + cls->rvyuv_custom_message = dlsym (cls->rv_handle, "RV20toYUV420CustomMessage"); + cls->rvyuv_free = dlsym (cls->rv_handle, "RV20toYUV420Free"); + cls->rvyuv_hive_message = dlsym (cls->rv_handle, "RV20toYUV420HiveMessage"); + cls->rvyuv_init = dlsym (cls->rv_handle, "RV20toYUV420Init"); + cls->rvyuv_transform = dlsym (cls->rv_handle, "RV20toYUV420Transform"); + + if (cls->rvyuv_custom_message && + cls->rvyuv_free && + cls->rvyuv_hive_message && + cls->rvyuv_init && + cls->rvyuv_transform) + return 1; + + printf ("libreal: Error resolving symbols! (version incompatibility?)\n"); + return 0; +} + +static void *init_class (xine_t *xine, void *data) { + + real_class_t *this; + + this = (real_class_t *) xine_xmalloc (sizeof (real_class_t)); + + if (!load_syms_linux (this, "/usr/local/RealPlayer8/Codecs/drv3.so.6.0")) { + free (this); + return NULL; + } + + 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; + + return this; +} + +/* + * exported plugin catalog entry + */ + +static uint32_t supported_types[] = { BUF_VIDEO_RV20, BUF_VIDEO_RV30, 0 }; + +static decoder_info_t dec_info_real = { + supported_types, /* supported types */ + 6 /* priority */ +}; + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_DECODER, 12, "real", XINE_VERSION_CODE, &dec_info_real, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index 292c1b461..cf59a9317 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.78 2002/11/15 00:20:34 miguelfreitas Exp $ + * $Id: buffer.h,v 1.79 2002/11/18 03:03:09 guenter Exp $ * * * contents: @@ -131,6 +131,8 @@ extern "C" { #define BUF_VIDEO_WC3 0x02300000 #define BUF_VIDEO_YV12 0x02310000 #define BUF_VIDEO_SEGA 0x02320000 +#define BUF_VIDEO_RV20 0x02330000 +#define BUF_VIDEO_RV30 0x02340000 /* audio buffer types: (please keep in sync with buffer_types.c) */ @@ -168,6 +170,11 @@ extern "C" { #define BUF_AUDIO_GSM610 0x031E0000 #define BUF_AUDIO_EA_ADPCM 0x031F0000 #define BUF_AUDIO_WMAV2 0x03200000 +#define BUF_AUDIO_COOK 0x03210000 +#define BUF_AUDIO_ATRK 0x03220000 +#define BUF_AUDIO_14_4 0x03230000 +#define BUF_AUDIO_28_8 0x03240000 +#define BUF_AUDIO_SIPRO 0x03250000 /* spu buffer types: */ |