From 91bbcee4cf1f45d43e15b95a50bc8d59775c40ec Mon Sep 17 00:00:00 2001 From: Christophe Thommeret Date: Sun, 15 Feb 2009 03:43:48 +0000 Subject: New demuxer: demux_vc1es. --- src/demuxers/Makefile.am | 6 +- src/demuxers/demux_vc1es.c | 452 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 457 insertions(+), 1 deletion(-) create mode 100644 src/demuxers/demux_vc1es.c (limited to 'src') diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index 2c4b38e4a..0875672b2 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -48,7 +48,8 @@ xineplug_LTLIBRARIES = $(ogg_module) $(asf_module) $(mng_module) $(image_module) xineplug_dmx_nsv.la \ xineplug_dmx_matroska.la \ xineplug_dmx_iff.la \ - xineplug_dmx_flv.la + xineplug_dmx_flv.la \ + xineplug_dmx_vc1_es.la xineplug_dmx_ogg_la_SOURCES = demux_ogg.c xineplug_dmx_ogg_la_LIBADD = $(XINE_LIB) $(VORBIS_LIBS) $(SPEEX_LIBS) $(THEORA_LIBS) $(OGG_LIBS) $(LTLIBINTL) @@ -66,6 +67,9 @@ xineplug_dmx_mpeg_la_LIBADD = $(XINE_LIB) xineplug_dmx_mpeg_elem_la_SOURCES = demux_elem.c xineplug_dmx_mpeg_elem_la_LIBADD = $(XINE_LIB) +xineplug_dmx_vc1_es_la_SOURCES = demux_vc1es.c +xineplug_dmx_vc1_es_la_LIBADD = $(XINE_LIB) + xineplug_dmx_mpeg_pes_la_SOURCES = demux_mpeg_pes.c xineplug_dmx_mpeg_pes_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) diff --git a/src/demuxers/demux_vc1es.c b/src/demuxers/demux_vc1es.c new file mode 100644 index 000000000..1e970f72c --- /dev/null +++ b/src/demuxers/demux_vc1es.c @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2008 Christophe Thommeret + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +/* + * demultiplexer for wmv9/vc1 elementary streams + * + * + * SMP (.rcv) format: + * + * ** header *** + * le24 number of frames + * C5 04 00 00 00 + * 4 bytes sequence header + * le32 height + * le32 width + * 0C 00 00 00 + * 8 bytes unknown + * le32 fps + * ************ + * le24 frame_size + * 80 + * le32 pts (ms) + * frame_size bytes of picture data + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +/* #define LOG */ +#define LOG_MODULE "demux_vc1es" +#define LOG_VERBOSE + +#include "xine_internal.h" +#include "xineutils.h" +#include "compat.h" +#include "demux.h" + +#define SCRATCH_SIZE 36 +#define PRIVATE_SIZE 44 + +#define MODE_SMP 1 +#define MODE_AP 2 + + + +typedef struct { + demux_plugin_t demux_plugin; + + xine_stream_t *stream; + fifo_buffer_t *video_fifo; + fifo_buffer_t *audio_fifo; + input_plugin_t *input; + int status; + int mode; + int first_chunk; + uint8_t private[PRIVATE_SIZE]; + uint32_t video_step; + + uint32_t blocksize; +} demux_vc1_es_t ; + + + +typedef struct { + demux_class_t demux_class; +} demux_vc1_es_class_t; + + + +static int demux_vc1_es_next_smp( demux_vc1_es_t *this ) +{ + buf_element_t *buf; + uint32_t pts=0, frame_size=0; + off_t done; + uint8_t head[SCRATCH_SIZE]; + int start_flag = 1; + + if ( this->first_chunk ) { + this->input->read( this->input, head, SCRATCH_SIZE ); + this->first_chunk = 0; + } + + done = this->input->read( this->input, head, 8 ); + frame_size = head[2]<<16 | head[1]<<8 | head[0]; + pts = head[7]<<24 | head[6]<<16 | head[5]<<8 | head[4]; + + done = 0; + while ( frame_size>0 ) { + buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + off_t read = (frame_size>buf->max_size) ? buf->max_size : frame_size; + done = this->input->read( this->input, buf->mem, read ); + if ( done<=0 ) { + buf->free_buffer( buf ); + this->status = DEMUX_FINISHED; + return 0; + } + buf->size = done; + buf->content = buf->mem; + buf->type = BUF_VIDEO_WMV9; + buf->pts = pts*90; + frame_size -= done; + if ( start_flag ) { + buf->decoder_flags = BUF_FLAG_FRAME_START; + start_flag = 0; + } + if ( !(frame_size>0) ) + buf->decoder_flags = BUF_FLAG_FRAME_END; + this->video_fifo->put(this->video_fifo, buf); + } + + return 1; +} + + + +static int demux_vc1_es_next_ap( demux_vc1_es_t *this ) +{ + buf_element_t *buf; + uint32_t blocksize; + off_t done; + + buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + blocksize = (this->blocksize ? this->blocksize : buf->max_size); + done = this->input->read(this->input, buf->mem, blocksize); + + if (done <= 0) { + buf->free_buffer (buf); + this->status = DEMUX_FINISHED; + return 0; + } + + buf->size = done; + buf->content = buf->mem; + buf->pts = 0; + buf->type = BUF_VIDEO_VC1; + + if( this->input->get_length (this->input) ) + buf->extra_info->input_normpos = (int)( (double)this->input->get_current_pos( this->input )*65535/this->input->get_length( this->input ) ); + + this->video_fifo->put(this->video_fifo, buf); + + return 1; +} + + + +static int demux_vc1_es_send_chunk( demux_plugin_t *this_gen ) +{ + demux_vc1_es_t *this = (demux_vc1_es_t *) this_gen; + //printf ("demux_vc1_es_send_chunk\n"); + + if ( this->mode==MODE_SMP ) { + if (!demux_vc1_es_next_smp(this)) + this->status = DEMUX_FINISHED; + return this->status; + } + + if (!demux_vc1_es_next_ap(this)) + this->status = DEMUX_FINISHED; + return this->status; +} + + + +static int demux_vc1_es_get_status( demux_plugin_t *this_gen ) +{ + demux_vc1_es_t *this = (demux_vc1_es_t *) this_gen; + + return this->status; +} + + + +static void demux_vc1_es_send_headers( demux_plugin_t *this_gen ) +{ + demux_vc1_es_t *this = (demux_vc1_es_t *) this_gen; + + this->video_fifo = this->stream->video_fifo; + this->audio_fifo = this->stream->audio_fifo; + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 0); + _x_demux_control_start(this->stream); + this->blocksize = this->input->get_blocksize(this->input); + this->status = DEMUX_OK; + + if ( this->mode==MODE_SMP ) { + buf_element_t *buf; + buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + xine_fast_memcpy( buf->mem, this->private, PRIVATE_SIZE ); + buf->size = PRIVATE_SIZE; + buf->content = buf->mem; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + if ( this->video_step ) { + buf->decoder_flags |= BUF_FLAG_FRAMERATE; + buf->decoder_info[0] = 90000/this->video_step; + } + buf->type = BUF_VIDEO_WMV9; + this->video_fifo->put(this->video_fifo, buf); + } +} + + + +static int demux_vc1_es_seek( demux_plugin_t *this_gen, off_t start_pos, int start_time, int playing ) +{ + demux_vc1_es_t *this = (demux_vc1_es_t *) this_gen; + + if ( this->mode==MODE_SMP ) { + this->status = DEMUX_OK; + return this->status; + } + + start_pos = (off_t) ( (double) start_pos / 65535 * + this->input->get_length (this->input) ); + + this->status = DEMUX_OK; + + if (playing) + _x_demux_flush_engine(this->stream); + + if (INPUT_IS_SEEKABLE(this->input)) { + + /* FIXME: implement time seek */ + + if (start_pos != this->input->seek (this->input, start_pos, SEEK_SET)) { + this->status = DEMUX_FINISHED; + return this->status; + } + lprintf ("seeking to %"PRId64"\n", start_pos); + } + + /* + * now start demuxing + */ + this->status = DEMUX_OK; + + return this->status; +} + + + +static void demux_vc1_es_dispose( demux_plugin_t *this ) +{ + free (this); +} + + + +static int demux_vc1_es_get_stream_length( demux_plugin_t *this_gen ) +{ + return 0 ; /*FIXME: implement */ +} + + + +static uint32_t demux_vc1_es_get_capabilities( demux_plugin_t *this_gen ) +{ + return DEMUX_CAP_NOCAP; +} + + + +static int demux_vc1_es_get_optional_data( demux_plugin_t *this_gen, void *data, int data_type ) +{ + return DEMUX_OPTIONAL_UNSUPPORTED; +} + + + +static demux_plugin_t *open_plugin( demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input ) +{ + + demux_vc1_es_t *this; + uint8_t scratch[SCRATCH_SIZE]; + int i, read, found=0; + + switch (stream->content_detection_method) { + + case METHOD_BY_CONTENT: { + read = _x_demux_read_header(input, scratch, SCRATCH_SIZE); + if (!read) + return NULL; + lprintf("read size =%d\n",read); + + /* simple and main profiles */ + if ( read>=SCRATCH_SIZE ) { + lprintf("searching for rcv format..\n"); + if ( scratch[3]==0xc5 && scratch[4]==4 && scratch[5]==0 && scratch[6]==0 && scratch[7]==0 && scratch[20]==0x0c && scratch[21]==0 && scratch[22]==0 && scratch[23]==0 ) { + lprintf("rcv format found\n"); + found = MODE_SMP; + } + } + + if ( found==0 ) { + /* advanced profile */ + for (i = 0; i < read-4; i++) { + lprintf ("%02x %02x %02x %02x\n", scratch[i], scratch[i+1], scratch[i+2], scratch[i+3]); + if ((scratch[i] == 0x00) && (scratch[i+1] == 0x00) && (scratch[i+2] == 0x01)) { + if (scratch[i+3] == 0x0f) { + found = MODE_AP; + lprintf ("found header at offset 0x%x\n", i); + break; + } + } + } + } + + if (found == 0) + return NULL; + lprintf ("input accepted.\n"); + } + break; + + case METHOD_BY_EXTENSION: { + const char *extensions, *mrl; + + mrl = input->get_mrl (input); + extensions = class_gen->get_extensions (class_gen); + + if (!_x_demux_check_extension (mrl, extensions)) + return NULL; + } + break; + + case METHOD_EXPLICIT: + break; + + default: + return NULL; + } + + this = calloc(1, sizeof(demux_vc1_es_t)); + this->mode = found; + this->first_chunk = 1; + if ( found==MODE_SMP ) { + xine_fast_memcpy( this->private+8, scratch+12, 4 ); /* height */ + xine_fast_memcpy( this->private+4, scratch+16, 4 ); /* width */ + xine_fast_memcpy( this->private+40, scratch+8, 4 ); /* sequence header */ + } + this->video_step = scratch[35]<<24 | scratch[34]<<16 | scratch[33]<<8 | scratch[32]; + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = demux_vc1_es_send_headers; + this->demux_plugin.send_chunk = demux_vc1_es_send_chunk; + this->demux_plugin.seek = demux_vc1_es_seek; + this->demux_plugin.dispose = demux_vc1_es_dispose; + this->demux_plugin.get_status = demux_vc1_es_get_status; + this->demux_plugin.get_stream_length = demux_vc1_es_get_stream_length; + this->demux_plugin.get_capabilities = demux_vc1_es_get_capabilities; + this->demux_plugin.get_optional_data = demux_vc1_es_get_optional_data; + this->demux_plugin.demux_class = class_gen; + + this->status = DEMUX_FINISHED; + + return &this->demux_plugin; +} + + + +static const char *get_description( demux_class_t *this_gen ) +{ + return "VC1 elementary stream demux plugin"; +} + + + +static const char *get_identifier( demux_class_t *this_gen ) +{ + return "VC1_ES"; +} + + + +static const char *get_extensions( demux_class_t *this_gen ) +{ + return ""; +} + + + +static const char *get_mimetypes( demux_class_t *this_gen ) +{ + return NULL; +} + + + +static void class_dispose( demux_class_t *this_gen ) +{ + demux_vc1_es_class_t *this = (demux_vc1_es_class_t *) this_gen; + + free (this); +} + + + +static void *init_plugin( xine_t *xine, void *data ) +{ + demux_vc1_es_class_t *this; + + this = calloc(1, sizeof(demux_vc1_es_class_t)); + + 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; + + return this; +} + + +/* + * exported plugin catalog entry + */ +static const demuxer_info_t demux_info_vc1es = { + 0 /* priority */ +}; + + + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 26, "vc1es", XINE_VERSION_CODE, &demux_info_vc1es, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; -- cgit v1.2.3