summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2004-07-14 01:18:47 +0000
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2004-07-14 01:18:47 +0000
commit46df82be838571af99d0266f773b5fb274a924b5 (patch)
tree77a5cc43936b4ec376b4be7b48297be3858e1db3
parentbd4c703f8be11c6183229c472eeab239325aea58 (diff)
downloadxine-lib-46df82be838571af99d0266f773b5fb274a924b5.tar.gz
xine-lib-46df82be838571af99d0266f773b5fb274a924b5.tar.bz2
Moritz patch for matroska vobsub support
align vobsub to bottom in libspudec CVS patchset: 6791 CVS date: 2004/07/14 01:18:47
-rw-r--r--ChangeLog4
-rw-r--r--src/demuxers/demux_matroska.c257
-rw-r--r--src/demuxers/matroska.h16
-rw-r--r--src/libspudec/spu.c18
-rw-r--r--src/libspudec/spu.h3
-rw-r--r--src/libspudec/xine_decoder.c9
-rw-r--r--src/xine-engine/buffer.h4
7 files changed, 302 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 626c77833..84a57cb90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,8 +5,10 @@ xine-lib (1-rc6)
might lead to undefined behaviour; calling XInitThreads() is entirely
the frontend's job
* include goom2k4-dev15
+ * make sure the streams are played till their very end
* support for Annodex files
-
+ * VobSub-in-Matroska support
+
xine-lib (1-rc5)
* add support for ejecting removable media on Solaris
* fix stuttering playback of some realmedia streams
diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c
index b8442341c..d281590be 100644
--- a/src/demuxers/demux_matroska.c
+++ b/src/demuxers/demux_matroska.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: demux_matroska.c,v 1.28 2004/06/13 21:28:53 miguelfreitas Exp $
+ * $Id: demux_matroska.c,v 1.29 2004/07/14 01:18:48 miguelfreitas Exp $
*
* demultiplexer for matroska streams
*
@@ -32,11 +32,13 @@
#include "config.h"
#endif
+#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
+#include <zlib.h>
#define LOG_MODULE "demux_matroska"
#define LOG_VERBOSE
@@ -58,6 +60,13 @@
#define WRAP_THRESHOLD 90000
+#if !defined(MIN)
+#define MIN(a, b) ((a)<(b)?(a):(b))
+#endif
+#if !defined(MAX)
+#define MAX(a, b) ((a)>(b)?(a):(b))
+#endif
+
typedef struct {
int track_num;
off_t *pos;
@@ -508,6 +517,166 @@ static void init_codec_vorbis(demux_matroska_t *this, matroska_track_t *track) {
}
}
+
+static int vobsub_parse_size(matroska_track_t *t, const char *start) {
+ if (sscanf(&start[6], "%dx%d", &t->sub_track->width,
+ &t->sub_track->height) == 2) {
+ lprintf("VobSub size: %ux%u\n", t->sub_track->width, t->sub_track->height);
+ return 1;
+ }
+ return 0;
+}
+
+static int vobsub_parse_palette(matroska_track_t *t, const char *start) {
+ int i, r, g, b, y, u, v, tmp;
+
+ start += 8;
+ while (isspace(*start))
+ start++;
+ for (i = 0; i < 16; i++) {
+ if (sscanf(start, "%06x", &tmp) != 1)
+ break;
+ r = tmp >> 16 & 0xff;
+ g = tmp >> 8 & 0xff;
+ b = tmp & 0xff;
+ y = MIN(MAX((int)(0.1494 * r + 0.6061 * g + 0.2445 * b), 0), 0xff);
+ u = MIN(MAX((int)(0.6066 * r - 0.4322 * g - 0.1744 * b) + 128, 0), 0xff);
+ v = MIN(MAX((int)(-0.08435 * r - 0.3422 * g + 0.4266 * b) + 128, 0), 0xff);
+ t->sub_track->palette[i] = y << 16 | u << 8 | v;
+ start += 6;
+ while ((*start == ',') || isspace(*start))
+ start++;
+ }
+ if (i == 16) {
+ lprintf("VobSub palette: %06x,%06x,%06x,%06x,%06x,%06x,%06x,%06x,%06x,"
+ "%06x,%06x,%06x,%06x,%06x,%06x,%06x\n", t->sub_track->palette[0],
+ t->sub_track->palette[1], t->sub_track->palette[2],
+ t->sub_track->palette[3], t->sub_track->palette[4],
+ t->sub_track->palette[5], t->sub_track->palette[6],
+ t->sub_track->palette[7], t->sub_track->palette[8],
+ t->sub_track->palette[9], t->sub_track->palette[10],
+ t->sub_track->palette[11], t->sub_track->palette[12],
+ t->sub_track->palette[13], t->sub_track->palette[14],
+ t->sub_track->palette[15]);
+ return 2;
+ }
+ return 0;
+}
+
+static int vobsub_parse_custom_colors(matroska_track_t *t, const char *start) {
+ int use_custom_colors, i;
+
+ start += 14;
+ while (isspace(*start))
+ start++;
+ use_custom_colors = 0;
+ if (!strncasecmp(start, "ON", 2) || (*start == '1'))
+ use_custom_colors = 1;
+ else if (!strncasecmp(start, "OFF", 3) || (*start == '0'))
+ use_custom_colors = 0;
+ lprintf("VobSub custom colors: %s\n", use_custom_colors ? "ON" : "OFF");
+ if ((start = strstr(start, "colors:")) != NULL) {
+ start += 7;
+ while (isspace(*start))
+ start++;
+ for (i = 0; i < 4; i++) {
+ if (sscanf(start, "%06x", &t->sub_track->colors[i]) != 1)
+ break;
+ start += 6;
+ while ((*start == ',') || isspace(*start))
+ start++;
+ }
+ if (i == 4) {
+ t->sub_track->custom_colors = 4;
+ lprintf("VobSub colors: %06x,%06x,%06x,%06x\n", t->sub_track->colors[0],
+ t->sub_track->colors[1], t->sub_track->colors[2],
+ t->sub_track->colors[3]);
+ }
+ }
+ if (!use_custom_colors)
+ t->sub_track->custom_colors = 0;
+ return 4;
+}
+
+static int vobsub_parse_forced_subs(matroska_track_t *t, const char *start) {
+ start += 12;
+ while (isspace(*start))
+ start++;
+ if (!strncasecmp(start, "on", 2) || (*start == '1'))
+ t->sub_track->forced_subs_only = 1;
+ else if (!strncasecmp(start, "off", 3) || (*start == '0'))
+ t->sub_track->forced_subs_only = 0;
+ else
+ return 0;
+ lprintf("VobSub forced subs: %d\n", t->sub_track->forced_subs_only);
+ return 8;
+}
+
+static void init_codec_vobsub(demux_matroska_t *this,
+ matroska_track_t *track) {
+ int things_found, last;
+ char *buf, *pos, *start;
+ buf_element_t *buf_el;
+
+ lprintf("init_codec_vobsub for %d\n", track->track_num);
+
+ if ((track->codec_private == NULL) || (track->codec_private_len == 0))
+ return;
+
+ track->sub_track = calloc(1, sizeof(matroska_sub_track_t));
+ if (track->sub_track == NULL)
+ return;
+ things_found = 0;
+ buf = (char *)malloc(track->codec_private_len + 1);
+ if (buf == NULL)
+ return;
+ xine_fast_memcpy(buf, track->codec_private, track->codec_private_len);
+ buf[track->codec_private_len] = 0;
+ track->sub_track->type = 'v';
+
+ pos = buf;
+ start = buf;
+ last = 0;
+
+ do {
+ if ((*pos == 0) || (*pos == '\r') || (*pos == '\n')) {
+ if (*pos == 0)
+ last = 1;
+ *pos = 0;
+
+ if (!strncasecmp(start, "size: ", 6))
+ things_found |= vobsub_parse_size(track, start);
+ else if (!strncasecmp(start, "palette:", 8))
+ things_found |= vobsub_parse_palette(track, start);
+ else if (!strncasecmp(start, "custom colors:", 14))
+ things_found |= vobsub_parse_custom_colors(track, start);
+ else if (!strncasecmp(start, "forced subs:", 12))
+ things_found |= vobsub_parse_forced_subs(track, start);
+
+ if (last)
+ break;
+ do {
+ pos++;
+ } while ((*pos == '\r') || (*pos == '\n'));
+ start = pos;
+ } else
+ pos++;
+ } while (!last && (*start != 0));
+
+ free(buf);
+
+ if ((things_found & 2) == 2) {
+ buf_el = track->fifo->buffer_pool_alloc(track->fifo);
+ xine_fast_memcpy(buf_el->content, track->sub_track->palette,
+ 16 * sizeof(uint32_t));
+ buf_el->type = BUF_SPU_DVD;
+ buf_el->decoder_flags |= BUF_FLAG_SPECIAL;
+ buf_el->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE;
+ buf_el->decoder_info[2] = SPU_DVD_SUBTYPE_CLUT;
+ track->fifo->put(track->fifo, buf_el);
+ }
+}
+
static void handle_realvideo (demux_plugin_t *this_gen, matroska_track_t *track,
int decoder_flags,
uint8_t *data, int data_len,
@@ -665,6 +834,85 @@ static void handle_sub_utf8 (demux_plugin_t *this_gen, matroska_track_t *track,
}
+/* Note: This function assumes that the VobSub track is compressed with zlib.
+ * This is not necessarily true - or not enough. The Matroska 'content
+ * encoding' elements allow for a layer of changes applied to the contents,
+ * e.g. compression or encryption. Anyway, only zlib compression is used
+ * at the moment, and everyone compresses the VobSubs.
+ */
+static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track,
+ int decoder_flags,
+ uint8_t *data, int data_len,
+ int64_t data_pts, int data_duration,
+ int input_normpos, int input_time) {
+ demux_matroska_t *this = (demux_matroska_t *) this_gen;
+ buf_element_t *buf;
+ z_stream zstream;
+ uint8_t *dest;
+ int old_data_len, result;
+
+ old_data_len = data_len;
+ zstream.zalloc = (alloc_func) 0;
+ zstream.zfree = (free_func) 0;
+ zstream.opaque = (voidpf) 0;
+ if (inflateInit (&zstream) != Z_OK) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ "demux_matroska: VobSub: zlib inflateInit failed.\n");
+ return;
+ }
+ zstream.next_in = (Bytef *)data;
+ zstream.avail_in = data_len;
+
+ dest = (uint8_t *)malloc(data_len);
+ zstream.avail_out = data_len;
+ do {
+ data_len += 4000;
+ dest = (uint8_t *)realloc(dest, data_len);
+ zstream.next_out = (Bytef *)(dest + zstream.total_out);
+ result = inflate (&zstream, Z_NO_FLUSH);
+ if ((result != Z_OK) && (result != Z_STREAM_END)) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ "demux_matroska: VobSub: zlib decompression failed.\n");
+ free(dest);
+ inflateEnd(&zstream);
+ return;
+ }
+ zstream.avail_out += 4000;
+ } while ((zstream.avail_out == 4000) &&
+ (zstream.avail_in != 0) && (result != Z_STREAM_END));
+
+ data_len = zstream.total_out;
+ inflateEnd(&zstream);
+
+ lprintf("VobSub: decompression for track %d from %d to %d\n",
+ (int)track->track_num, old_data_len, data_len);
+
+ buf = track->fifo->buffer_pool_alloc(track->fifo);
+
+ buf->size = data_len;
+ if (buf->max_size >= buf->size) {
+ buf->decoder_flags = decoder_flags | BUF_FLAG_SPECIAL;
+ buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE;
+ buf->decoder_info[2] = SPU_DVD_SUBTYPE_VOBSUB_PACKAGE;
+ buf->type = track->buf_type;
+
+ xine_fast_memcpy(buf->content, dest, data_len);
+
+ buf->extra_info->input_normpos = input_normpos;
+ buf->extra_info->input_time = input_time;
+
+ buf->pts = data_pts;
+ track->fifo->put(track->fifo, buf);
+
+ } else {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ "demux_matroska: VobSub: data length is greater than fifo buffer length\n");
+ buf->free_buffer(buf);
+ }
+
+ free(dest);
+}
+
static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) {
ebml_parser_t *ebml = this->ebml;
int next_level = 3;
@@ -888,6 +1136,11 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) {
lprintf("MATROSKA_CODEC_ID_S_TEXT_USF\n");
track->buf_type = BUF_SPU_OGM;
track->handle_content = handle_sub_utf8;
+ } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_S_VOBSUB)) {
+ lprintf("MATROSKA_CODEC_ID_S_VOBSUB\n");
+ track->buf_type = BUF_SPU_DVD;
+ track->handle_content = handle_vobsub;
+ init_codec = init_codec_vobsub;
} else {
lprintf("unknown codec\n");
}
@@ -2093,6 +2346,8 @@ static void demux_matroska_dispose (demux_plugin_t *this_gen) {
free (track->video_track);
if (track->audio_track)
free (track->audio_track);
+ if (track->sub_track)
+ free (track->sub_track);
free (track);
}
diff --git a/src/demuxers/matroska.h b/src/demuxers/matroska.h
index 2c887f152..a203b2e2f 100644
--- a/src/demuxers/matroska.h
+++ b/src/demuxers/matroska.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: matroska.h,v 1.7 2004/06/13 21:28:55 miguelfreitas Exp $
+ * $Id: matroska.h,v 1.8 2004/07/14 01:18:48 miguelfreitas Exp $
*
*/
#ifndef MATROSKA_H
@@ -201,6 +201,18 @@ typedef struct {
int bits_per_sample;
} matroska_audio_track_t;
+typedef struct {
+ char type;
+
+ /* The rest is used for VobSubs (type = 'v'). */
+ int width;
+ int height;
+ uint32_t palette[16];
+ int custom_colors;
+ uint32_t colors[4];
+ int forced_subs_only;
+} matroska_sub_track_t;
+
typedef struct matroska_track_s matroska_track_t;
struct matroska_track_s {
int track_num;
@@ -218,6 +230,7 @@ struct matroska_track_s {
matroska_video_track_t *video_track;
matroska_audio_track_t *audio_track;
+ matroska_sub_track_t *sub_track;
int64_t last_pts;
@@ -275,6 +288,7 @@ struct matroska_track_s {
#define MATROSKA_CODEC_ID_S_UTF8 "S_UTF8" /* deprecated */
#define MATROSKA_CODEC_ID_S_SSA "S_SSA" /* deprecated */
#define MATROSKA_CODEC_ID_S_ASS "S_ASS" /* deprecated */
+#define MATROSKA_CODEC_ID_S_VOBSUB "S_VOBSUB"
/* block lacing */
#define MATROSKA_NO_LACING 0x0
diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c
index 8d4bdcc5e..336837737 100644
--- a/src/libspudec/spu.c
+++ b/src/libspudec/spu.c
@@ -36,7 +36,7 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: spu.c,v 1.76 2004/06/26 13:49:54 mroi Exp $
+ * $Id: spu.c,v 1.77 2004/07/14 01:18:48 miguelfreitas Exp $
*
*/
@@ -488,6 +488,22 @@ void spudec_process (spudec_decoder_t *this, int stream_id) {
spudec_discover_clut(this->stream->xine, &this->state, &this->overlay);
}
+ if (this->state.vobsub) {
+ int width, height;
+ int64_t duration;
+
+ /*
+ * vobsubs are usually played with a scaled-down stream (not full DVD
+ * resolution), therefore we should try to realign it.
+ */
+
+ this->stream->video_out->status(this->stream->video_out, NULL,
+ &width, &height, &duration );
+
+ this->overlay.x = (width - this->overlay.width) / 2;
+ this->overlay.y = height - this->overlay.height;
+ }
+
/* Subtitle */
if( this->menu_handle < 0 ) {
this->menu_handle = ovl_manager->get_handle(ovl_manager,1);
diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h
index 6da793f1c..91f4f8ab6 100644
--- a/src/libspudec/spu.h
+++ b/src/libspudec/spu.h
@@ -19,7 +19,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: spu.h,v 1.26 2004/06/21 16:19:41 mroi Exp $
+ * $Id: spu.h,v 1.27 2004/07/14 01:18:48 miguelfreitas Exp $
*
* This file was originally part of the OMS program.
*
@@ -85,6 +85,7 @@ typedef struct {
int32_t delay; /* Delay in 90Khz / 1000 */
int32_t need_clut; /* doesn't have the right clut yet */
int32_t cur_colors[4];/* current 4 colors been used */
+ int32_t vobsub; /* vobsub must be aligned to bottom */
uint32_t clut[16];
} spudec_state_t;
diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c
index 5fa10b944..985d3305d 100644
--- a/src/libspudec/xine_decoder.c
+++ b/src/libspudec/xine_decoder.c
@@ -19,7 +19,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: xine_decoder.c,v 1.107 2004/06/21 16:19:41 mroi Exp $
+ * $Id: xine_decoder.c,v 1.108 2004/07/14 01:18:48 miguelfreitas Exp $
*
* stuff needed to turn libspu into a xine decoder plugin
*/
@@ -108,7 +108,11 @@ static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
spudec_decode_nav(this,buf);
return;
}
-
+
+ if ( buf->decoder_info[2] == SPU_DVD_SUBTYPE_VOBSUB_PACKAGE ) {
+ this->state.vobsub = 1;
+ }
+
/* check, if we need to process the next PCI from the list */
pthread_mutex_lock(&this->nav_pci_lock);
spudec_update_nav(this);
@@ -338,6 +342,7 @@ static spu_decoder_t *open_plugin (spu_decoder_class_t *class_gen, xine_stream_t
/* FIXME:Do we really need a default clut? */
xine_fast_memcpy(this->state.clut, __default_clut, sizeof(this->state.clut));
this->state.need_clut = 1;
+ this->state.vobsub = 0;
return &this->spu_decoder;
}
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index a9239aaea..9295356b4 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.139 2004/06/21 16:19:40 mroi Exp $
+ * $Id: buffer.h,v 1.140 2004/07/14 01:18:47 miguelfreitas Exp $
*
*
* contents:
@@ -442,7 +442,7 @@ struct buf_element_s {
#define SPU_DVD_SUBTYPE_CLUT 1
#define SPU_DVD_SUBTYPE_PACKAGE 2
-/* FIXME: number 3 is unused */
+#define SPU_DVD_SUBTYPE_VOBSUB_PACKAGE 3
#define SPU_DVD_SUBTYPE_NAV 4
/* In a BUF_SPECIAL_SPU_DVB_DESCRIPTOR