From 6b602efd6d83a311f0c863c35bada02f1f985554 Mon Sep 17 00:00:00 2001 From: Ross Alexander Date: Fri, 3 Apr 2009 17:52:13 +0100 Subject: Add support for Matroska SIMPLEBLOCK. Date: Tue, 17 Feb 2009 15:31:44 +0000 --- src/demuxers/demux_matroska.c | 36 ++++++++++++++++++++++++++++++++++-- src/demuxers/matroska.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index 37f4bd95b..5cf783bf5 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -2078,6 +2078,31 @@ static int parse_block (demux_matroska_t *this, size_t block_size, return 1; } +static int parse_simpleblock(demux_matroska_t *this, size_t block_len, uint64_t cluster_timecode, uint64_t block_duration) +{ + int has_block = 0; + off_t block_pos = 0; + off_t file_len = 0; + int normpos = 0; + int is_key = 1; + + lprintf("simpleblock\n"); + block_pos = this->input->get_current_pos(this->input); + file_len = this->input->get_length(this->input); + if( file_len ) + normpos = (int) ( (double) block_pos * 65535 / file_len ); + + if (!read_block_data(this, block_len)) + return 0; + + has_block = 1; + /* we have the duration, we can parse the block now */ + if (!parse_block(this, block_len, cluster_timecode, block_duration, + normpos, is_key)) + return 0; + return 1; +} + static int parse_block_group(demux_matroska_t *this, uint64_t cluster_timecode, uint64_t cluster_duration) { @@ -2142,7 +2167,8 @@ static int parse_block_group(demux_matroska_t *this, static int parse_cluster(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; - int next_level = 2; + int this_level = ebml->level; + int next_level = this_level; uint64_t timecode = 0; uint64_t duration = 0; @@ -2159,7 +2185,7 @@ static int parse_cluster(demux_matroska_t *this) { this->first_cluster_found = 1; } - while (next_level == 2) { + while (next_level == this_level) { ebml_elem_t elem; if (!ebml_read_elem_head(ebml, &elem)) @@ -2183,6 +2209,11 @@ static int parse_cluster(demux_matroska_t *this) { if ((elem.len > 0) && !parse_block_group(this, timecode, duration)) return 0; break; + case MATROSKA_ID_CL_SIMPLEBLOCK: + lprintf("simpleblock\n"); + if (!parse_simpleblock(this, elem.len, timecode, duration)) + return 0; + break; case MATROSKA_ID_CL_BLOCK: lprintf("block\n"); if (!ebml_skip(ebml, &elem)) @@ -2329,6 +2360,7 @@ static int parse_top_level_head(demux_matroska_t *this, int *next_level) { ebml_elem_t elem; int ret_value = 1; off_t current_pos; + current_pos = this->input->get_current_pos(this->input); lprintf("current_pos: %" PRIdMAX "\n", (intmax_t)current_pos); diff --git a/src/demuxers/matroska.h b/src/demuxers/matroska.h index 23af84af0..df6e8ad1b 100644 --- a/src/demuxers/matroska.h +++ b/src/demuxers/matroska.h @@ -62,6 +62,7 @@ #define MATROSKA_ID_CL_BLOCKGROUP 0xA0 #define MATROSKA_ID_CL_BLOCK 0xA1 #define MATROSKA_ID_CL_BLOCKVIRTUAL 0xA2 +#define MATROSKA_ID_CL_SIMPLEBLOCK 0xA3 #define MATROSKA_ID_CL_BLOCKADDITIONS 0x75A1 #define MATROSKA_ID_CL_BLOCKMORE 0xA6 #define MATROSKA_ID_CL_BLOCKADDID 0xEE -- cgit v1.2.3 From 93e18cdcc4e4a0a16b772f25bb45741fb537492c Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Wed, 18 Feb 2009 02:09:49 +0000 Subject: Add support for new OpenBSD sound API --- src/audio_out/Makefile.am | 12 +- src/audio_out/audio_sndio_out.c | 410 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 src/audio_out/audio_sndio_out.c (limited to 'src') diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am index 40d3c6cca..07ad19c8d 100644 --- a/src/audio_out/Makefile.am +++ b/src/audio_out/Makefile.am @@ -50,6 +50,10 @@ if HAVE_JACK jack_module = xineplug_ao_out_jack.la endif +if HAVE_SNDIO +sndio_module = xineplug_ao_out_sndio.la +endif + ## # IMPORTANT: # --------- @@ -67,7 +71,8 @@ xineplug_LTLIBRARIES = xineplug_ao_out_none.la xineplug_ao_out_file.la \ $(pulseaudio_module) \ $(directx2_module) \ $(fusionsound_module) \ - $(jack_module) + $(jack_module) \ + $(sndio_module) xineplug_ao_out_none_la_SOURCES = audio_none_out.c xineplug_ao_out_none_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) @@ -145,3 +150,8 @@ xineplug_ao_out_jack_la_SOURCES = audio_jack_out.c xineplug_ao_out_jack_la_LIBADD = $(XINE_LIB) $(JACK_LIBS) $(LTLIBINTL) xineplug_ao_out_jack_la_CFLAGS = $(VISIBILITY_FLAG) $(JACK_CFLAGS) xineplug_ao_out_jack_la_LDFLAGS = -avoid-version -module + +xineplug_ao_out_sndio_la_SOURCES = audio_sndio_out.c +xineplug_ao_out_sndio_la_LIBADD = $(XINE_LIB) $(SNDIO_LIBS) +xineplug_ao_out_sndio_la_CFLAGS = $(VISIBILITY_FLAG) $(SNDIO_CFLAGS) +xineplug_ao_out_sndio_la_LDFLAGS = -avoid-version -module diff --git a/src/audio_out/audio_sndio_out.c b/src/audio_out/audio_sndio_out.c new file mode 100644 index 000000000..7c3040e6e --- /dev/null +++ b/src/audio_out/audio_sndio_out.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2008 Brad Smith + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ao plugin for sndio by Brad Smith . */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xine_internal.h" +#include "xineutils.h" +#include "audio_out.h" +#include "bswap.h" + +#define GAP_TOLERANCE AO_MAX_GAP +#define PCT_TO_MIDI(p) (((p) * SIO_MAXVOL + 50) / 100) + +typedef struct { + audio_driver_class_t driver_class; + xine_t *xine; +} sndio_class_t; + +typedef struct sndio_driver_s { + ao_driver_t ao_driver; + xine_t *xine; + + struct sio_hdl *hdl; + long long realpos, playpos; + int capabilities; + + int num_channels; + u_int32_t bits_per_sample; + u_int32_t bytes_per_frame; + + struct { + int volume; + int mute; + } mixer; +} sndio_driver_t; + +/* + * Callback to notify of frames processed by the hw. It is + * called from the mail loop called from sio_write(). + */ +static void ao_sndio_onmove_cb(void *addr, int delta) +{ + sndio_driver_t *this = (sndio_driver_t *)addr; + + this->realpos += delta; +} + +/* + * Open the audio device for writing to. + */ +static int ao_sndio_open(ao_driver_t *this_gen, + uint32_t bits, uint32_t rate, int mode) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + struct sio_par par; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open bits=%d rate=%d, mode=%d\n", + bits, rate, mode); + + if (this->hdl != NULL) { + sio_close (this->hdl); + this->hdl = NULL; + } + + this->hdl = sio_open(NULL, SIO_PLAY, 0); + if (this->hdl == NULL) + goto bad; + + sio_initpar(&par); + + switch (mode) { + case AO_CAP_MODE_MONO: + par.pchan = 1; + break; + case AO_CAP_MODE_STEREO: + par.pchan = 2; + break; + case AO_CAP_MODE_4CHANNEL: + par.pchan = 4; + break; + case AO_CAP_MODE_4_1CHANNEL: + case AO_CAP_MODE_5CHANNEL: + case AO_CAP_MODE_5_1CHANNEL: + par.pchan = 6; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open does not support the requested mode: 0x%X\n", + mode); + goto bad; + } + + switch (bits) { + case 8: + par.bits = 8; + par.sig = 0; + break; + case 16: + par.bits = 16; + par.sig = 1; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open bits per sample not supported: %d\n", bits); + goto bad; + } + + par.rate = rate; + par.appbufsz = par.rate * 250 / 1000; /* 250ms buffer */ + + if (!sio_setpar(this->hdl, &par)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not set params\n"); + goto bad; + } + + if (!sio_getpar(this->hdl, &par)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not get params\n"); + goto bad; + } + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open %d channels output\n", + par.pchan); + + this->num_channels = par.pchan; + this->bytes_per_frame = par.bps * par.pchan; + this->playpos = 0; + this->realpos = 0; + sio_onmove(this->hdl, ao_sndio_onmove_cb, this); + + if (!sio_start(this->hdl)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not start\n"); + goto bad; + } + + return par.rate; + +bad: + if (this->hdl != NULL) + sio_close(this->hdl); + return 0; +} + +static int ao_sndio_num_channels(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->num_channels; +} + +static int ao_sndio_bytes_per_frame(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->bytes_per_frame; +} + +static int ao_sndio_get_gap_tolerance (ao_driver_t *this_gen) +{ + return GAP_TOLERANCE; +} + +static int ao_sndio_write(ao_driver_t *this_gen, int16_t *data, + uint32_t num_frames) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + size_t ret, size = num_frames * this->bytes_per_frame; + + ret = sio_write(this->hdl, data, size); + if (ret == 0) + return 0; + + this->playpos += num_frames; + + return 1; +} + +static int ao_sndio_delay (ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + int bufused; + + if (this->realpos < 0) + bufused = this->playpos; + else + bufused = this->playpos - this->realpos; + + return bufused; +} + +static void ao_sndio_close(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_close called\n"); + + if (!sio_stop(this->hdl)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_close could not stop\n"); + } + + sio_close(this->hdl); + this->hdl = NULL; +} + +static uint32_t ao_sndio_get_capabilities (ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->capabilities; +} + +static void ao_sndio_exit(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_exit called\n"); + + if (this->hdl != NULL) + sio_close(this->hdl); +} + +static int ao_sndio_get_property (ao_driver_t *this_gen, int property) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + switch (property) { + case AO_PROP_MIXER_VOL: + return this->mixer.volume; + break; + case AO_PROP_MUTE_VOL: + return this->mixer.mute; + break; + } + + return 0; +} + +static int ao_sndio_set_property (ao_driver_t *this_gen, int property, int value) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + int vol; + + if (this->hdl == NULL) + return 0; + + switch(property) { + case AO_PROP_MIXER_VOL: + this->mixer.volume = value; + if (!this->mixer.mute) + sio_setvol(this->hdl, PCT_TO_MIDI(this->mixer.volume)); + return this->mixer.volume; + break; + + case AO_PROP_MUTE_VOL: + this->mixer.mute = (value) ? 1 : 0; + vol = 0; + if (!this->mixer.mute) + vol = PCT_TO_MIDI(this->mixer.volume); + sio_setvol(this->hdl, vol); + return value; + break; + } + + return value; +} + +/* + * pause, resume, flush buffers + */ +static int ao_sndio_ctrl(ao_driver_t *this_gen, int cmd, ...) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + /* + * sndio pauses automatically if there are no more samples to play + * and resumes when there are samples again. So we leave this empty + * for the moment. + */ + + return 0; +} + +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) +{ + sndio_class_t *class = (sndio_class_t *) class_gen; + sndio_driver_t *this; + + lprintf ("audio_sndio_out: open_plugin called\n"); + + this = calloc(1, sizeof (sndio_driver_t)); + if (!this) + return NULL; + + this->xine = class->xine; + + /* + * Set capabilities + */ + this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | + AO_CAP_MODE_4CHANNEL | AO_CAP_MODE_4_1CHANNEL | + AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL | + AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS | + AO_CAP_16BITS; + + this->ao_driver.get_capabilities = ao_sndio_get_capabilities; + this->ao_driver.get_property = ao_sndio_get_property; + this->ao_driver.set_property = ao_sndio_set_property; + this->ao_driver.open = ao_sndio_open; + this->ao_driver.num_channels = ao_sndio_num_channels; + this->ao_driver.bytes_per_frame = ao_sndio_bytes_per_frame; + this->ao_driver.delay = ao_sndio_delay; + this->ao_driver.write = ao_sndio_write; + this->ao_driver.close = ao_sndio_close; + this->ao_driver.exit = ao_sndio_exit; + this->ao_driver.get_gap_tolerance = ao_sndio_get_gap_tolerance; + this->ao_driver.control = ao_sndio_ctrl; + + return &this->ao_driver; +} + +/* + * class functions + */ + +static char* get_identifier (audio_driver_class_t *this_gen) +{ + return "sndio"; +} + +static char* get_description (audio_driver_class_t *this_gen) +{ + return _("xine audio output plugin using sndio audio devices/drivers "); +} + +static void dispose_class (audio_driver_class_t *this_gen) +{ + sndio_class_t *this = (sndio_class_t *) this_gen; + + free(this); +} + +static void *init_class (xine_t *xine, void *data) +{ + sndio_class_t *this; + + lprintf ("audio_sndio_out: init class\n"); + + this = calloc(1, sizeof (sndio_class_t)); + if (!this) + return NULL; + + this->driver_class.open_plugin = open_plugin; + this->driver_class.get_identifier = get_identifier; + this->driver_class.get_description = get_description; + this->driver_class.dispose = dispose_class; + + this->xine = xine; + + return this; +} + +static const ao_info_t ao_info_sndio = { + 12 +}; + +/* + * exported plugin catalog entry + */ + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, 8, "sndio", XINE_VERSION_CODE, &ao_info_sndio, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; -- cgit v1.2.3 From cb365e0071d2e540eb706f2bdce6f351c206efa5 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 4 Apr 2009 00:08:22 +0100 Subject: Correct invalid MIME info in the MOD demuxer. --- src/demuxers/demux_mod.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/demuxers/demux_mod.c b/src/demuxers/demux_mod.c index c67f6e18e..34b8ebabe 100644 --- a/src/demuxers/demux_mod.c +++ b/src/demuxers/demux_mod.c @@ -387,11 +387,11 @@ static const char *get_mimetypes (demux_class_t *this_gen) { "audio/x-s3m: s3m: ScreamTracker 3 Module;" "audio/s3m: s3m: ScreamTracker 3 Module;" "application/playerpro: 669: 669 Tracker Module;" - "application/adrift; amf: ADRIFT Module File;" - "audio/med; med; Amiga MED/OctaMED Tracker Module Sound File;" - "audio/x-amf; amf: ADRIFT Module File;" - "audio/x-xm; xm: FastTracker II Audio;" - "audio/xm; xm: FastTracker II Audio;"; + "application/adrift: amf: ADRIFT Module File;" + "audio/med: med: Amiga MED/OctaMED Tracker Module Sound File;" + "audio/x-amf: amf: ADRIFT Module File;" + "audio/x-xm: xm: FastTracker II Audio;" + "audio/xm: xm: FastTracker II Audio;"; } static void class_dispose (demux_class_t *this_gen) { -- cgit v1.2.3 From 094656d55e8cf2b685fadea1aeffee4fb59f4449 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 5 Apr 2009 00:05:55 +0100 Subject: Fix a resource leak in libdvdnav. --- src/input/libdvdnav/remap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/input/libdvdnav/remap.c b/src/input/libdvdnav/remap.c index 43c81c66f..df0be29ce 100644 --- a/src/input/libdvdnav/remap.c +++ b/src/input/libdvdnav/remap.c @@ -216,6 +216,7 @@ remap_t* remap_loadmap( char *title) { remap_add_node( map, tmp); } } + close (fp); /* ignoring errors... */ if (map->nblocks == 0 && map->debug == 0) return NULL; return map; -- cgit v1.2.3 From 240889c0d0a7ead9df29c5d154403490fb09e8c7 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 5 Apr 2009 02:36:17 +0100 Subject: Properly NUL-terminate when reading ID3v2.2 tag content. --- src/demuxers/id3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c index c6f261468..1aebbc817 100644 --- a/src/demuxers/id3.c +++ b/src/demuxers/id3.c @@ -286,6 +286,7 @@ static int id3v22_interp_frame(input_plugin_t *input, } if (input->read (input, buf, frame_header->size) == frame_header->size) { + buf[frame_header->size] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; -- cgit v1.2.3 From a6bc7ed17d202107208bbe637ca92d5886c3d686 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 5 Apr 2009 18:39:10 +0100 Subject: Fix handling of the length of UTF-16 content sourced from, e.g., ID3 tags. This avoids use of strlen(), which doesn't cope well with UTF-16, and also has the ID3 parser double-NUL-terminate the buffered string. --- src/demuxers/id3.c | 15 +++++++++------ src/xine-engine/info_helper.c | 10 +++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c index 1aebbc817..0d0ee7231 100644 --- a/src/demuxers/id3.c +++ b/src/demuxers/id3.c @@ -275,8 +275,8 @@ static int id3v22_interp_frame(input_plugin_t *input, id3v22_frame_header_t *frame_header) { char *buf; int enc; - const size_t bufsize = frame_header->size +1; - if ( bufsize <= 2 ) /* frames has to be _at least_ 1 byte */ + const size_t bufsize = frame_header->size + 2; + if ( bufsize <= 3 ) /* frames has to be _at least_ 1 byte */ return 0; buf = malloc(bufsize); @@ -287,6 +287,7 @@ static int id3v22_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; @@ -472,8 +473,8 @@ static int id3v23_interp_frame(input_plugin_t *input, id3v23_frame_header_t *frame_header) { char *buf; int enc; - const size_t bufsize = frame_header->size +1; - if ( bufsize <= 2 ) /* frames has to be _at least_ 1 byte */ + const size_t bufsize = frame_header->size + 2; + if ( bufsize <= 3 ) /* frames has to be _at least_ 1 byte */ return 0; buf = malloc(bufsize); @@ -484,6 +485,7 @@ static int id3v23_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; @@ -726,8 +728,8 @@ static int id3v24_interp_frame(input_plugin_t *input, id3v24_frame_header_t *frame_header) { char *buf; int enc; - const size_t bufsize = frame_header->size +1; - if ( bufsize <= 2 ) /* frames has to be _at least_ 1 byte */ + const size_t bufsize = frame_header->size + 2; + if ( bufsize <= 3 ) /* frames has to be _at least_ 1 byte */ return 0; buf = malloc(bufsize); @@ -738,6 +740,7 @@ static int id3v24_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; diff --git a/src/xine-engine/info_helper.c b/src/xine-engine/info_helper.c index 34d1bbdba..6ce9bcd38 100644 --- a/src/xine-engine/info_helper.c +++ b/src/xine-engine/info_helper.c @@ -251,7 +251,15 @@ static void meta_info_set_unlocked_encoding(xine_stream_t *stream, int info, con size_t inbytesleft, outbytesleft; inbuf = (ICONV_CONST char *)value; - inbytesleft = strlen(value); + if (!strncmp (enc, "UTF-16", 6) || !strncmp (enc, "UCS-2", 5)) + { + /* strlen() won't work with UTF-16* or UCS-2* */ + inbytesleft = 0; + while (value[inbytesleft] || value[inbytesleft + 1]) + inbytesleft += 2; + } /* ... do we need to handle UCS-4? Probably not. */ + else + inbytesleft = strlen(value); outbytesleft = 4 * inbytesleft; /* estimative (max) */ outbuf = utf8_value = malloc(outbytesleft+1); -- cgit v1.2.3