diff options
author | phintuka <phintuka> | 2013-08-20 09:42:46 +0000 |
---|---|---|
committer | phintuka <phintuka> | 2013-08-20 09:42:46 +0000 |
commit | 62abdbaaab3651afd602ba8baec77056442c9a99 (patch) | |
tree | 1b3d71eb08929ced9850bbcd8f2793b1858797c5 | |
parent | a134830daa529265d16d78f58664d2e1a05d3628 (diff) | |
download | xineliboutput-62abdbaaab3651afd602ba8baec77056442c9a99.tar.gz xineliboutput-62abdbaaab3651afd602ba8baec77056442c9a99.tar.bz2 |
Removed old xine bluray plugins
-rw-r--r-- | xine/BluRay/Makefile | 166 | ||||
-rw-r--r-- | xine/BluRay/decode_spuhdmv.c | 1103 | ||||
-rw-r--r-- | xine/BluRay/demux_ts.c | 2783 | ||||
-rw-r--r-- | xine/BluRay/input_bluray.c | 1980 | ||||
-rw-r--r-- | xine/BluRay/xine_lpcm_decoder.c | 424 |
5 files changed, 0 insertions, 6456 deletions
diff --git a/xine/BluRay/Makefile b/xine/BluRay/Makefile deleted file mode 100644 index b442500b..00000000 --- a/xine/BluRay/Makefile +++ /dev/null @@ -1,166 +0,0 @@ -# -# select plugins -# - -ifeq ($(shell pkg-config libxine --atleast-version=1.1.21 || echo "yes"), yes) - ENABLE_DEMUX_PLUGIN ?= yes -else - ENABLE_DEMUX_PLUGIN ?= no - $(warning demux plugin is included in xine-lib 1.1.21+) -endif - -ifeq ($(shell pkg-config libbluray && echo yes), yes) - ifeq ($(shell pkg-config libxine --atleast-version=1.1.21 || echo "yes"), yes) - ENABLE_INPUT_PLUGIN ?= yes - CFLAGS_BD ?= $(shell pkg-config libbluray --cflags) - LIBS_BD ?= $(shell pkg-config libbluray --libs) - else - ENABLE_DEMUX_PLUGIN ?= no - $(warning input plugin is included in xine-lib 1.1.21+) - endif -else - ENABLE_INPUT_PLUGIN ?= no - $(warning libbluray not found) -endif - -ifeq ($(shell pkg-config libxine --atleast-version=1.1.19.1 || echo "yes"), yes) - ENABLE_SPU_PLUGIN ?= yes -else - ENABLE_SPU_PLUGIN ?= no - $(warning SPU plugin is included in xine-lib 1.1.19+) -endif - -ifeq ($(shell pkg-config libxine --atleast-version=1.1.19.1 || echo "yes"), yes) - ENABLE_PCM_PLUGIN ?= yes -else - ENABLE_PCM_PLUGIN ?= no - $(warning PCM plugin is included in xine-lib 1.1.19+) -endif - -# -# compiler options -# - -CFLAGS += -O2 -fPIC -ggdb -CFLAGS += -Wall -Wextra -Wno-unused-parameter -CFLAGS += -D_REENTRANT -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -CFLAGS += $(shell pkg-config libxine --cflags) -CFLAGS += $(CFLAGS_BD) -INSTALL = install - - -# -# linker options -# - -LIBS_XINE = $(shell pkg-config libxine --libs) -LDFLAGS += -shared -fvisibility=hidden - -# -# targets -# - -DESTDIR ?= / -XINEPLUGINDIR = $(shell pkg-config libxine --variable=plugindir) - -ifeq ($(ENABLE_DEMUX_PLUGIN), yes) - XINEDMXPLUGIN = xineplug_dmx_mpeg_ts_hdmv.so -else - $(warning Not building HDMV MPEG-TS demuxer plugin) -endif - -ifeq ($(ENABLE_SPU_PLUGIN), yes) - XINESPUPLUGIN = xineplug_decode_spuhdmv.so -else - $(warning Not building HDMV SPU plugin) -endif - -ifeq ($(ENABLE_INPUT_PLUGIN), yes) - XINEINPUTPLUGIN= xineplug_inp_bluray.so -else - $(warning Not building BluRay input plugin) -endif - -ifeq ($(ENABLE_PCM_PLUGIN), yes) - XINELPCMPLUGIN = xineplug_decode_lpcm_hdmv.so -else - $(warning Not building BluRay PCM plugin) -endif - -# -# object files -# - -OBJS_XINEDMXPLUGIN = demux_ts.o -OBJS_XINESPUPLUGIN = decode_spuhdmv.o -OBJS_XINEINPUTPLUGIN = input_bluray.o -OBJS_XINELPCMPLUGIN = xine_lpcm_decoder.o - -# -# rules -# - -all: $(XINEDMXPLUGIN) $(XINESPUPLUGIN) $(XINEINPUTPLUGIN) $(XINELPCMPLUGIN) - -ifeq ($(ENABLE_DEMUX_PLUGIN), yes) -$(XINEDMXPLUGIN): $(OBJS_XINEDMXPLUGIN) - $(CC) $(LDFLAGS) $(LIBS_XINE) -o $@ $(OBJS_XINEDMXPLUGIN) -endif - -ifeq ($(ENABLE_SPU_PLUGIN), yes) -$(XINESPUPLUGIN): $(OBJS_XINESPUPLUGIN) - $(CC) $(LDFLAGS) $(LIBS_XINE) -o $@ $(OBJS_XINESPUPLUGIN) -endif - -ifeq ($(ENABLE_INPUT_PLUGIN), yes) -$(XINEINPUTPLUGIN): $(OBJS_XINEINPUTPLUGIN) - $(CC) $(LDFLAGS) $(LIBS_XINE) $(LIBS_BD) -o $@ $(OBJS_XINEINPUTPLUGIN) -endif - -ifeq ($(ENABLE_PCM_PLUGIN), yes) -$(XINELPCMPLUGIN): $(OBJS_XINELPCMPLUGIN) - $(CC) $(LDFLAGS) $(LIBS_XINE) -o $@ $(OBJS_XINELPCMPLUGIN) -endif - -# -# targets -# - -clean: - @rm -rf *.o *.so *~ - -install: all uninstall -ifeq ($(ENABLE_DEMUX_PLUGIN), yes) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) - @$(INSTALL) -D -m 0644 $(XINEDMXPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) -endif -ifeq ($(ENABLE_SPU_PLUGIN), yes) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) - @$(INSTALL) -D -m 0644 $(XINESPUPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) -endif -ifeq ($(ENABLE_INPUT_PLUGIN), yes) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTPLUGIN) - @$(INSTALL) -D -m 0644 $(XINEINPUTPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTPLUGIN) -endif -ifeq ($(ENABLE_PCM_PLUGIN), yes) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINELPCMPLUGIN) - @$(INSTALL) -D -m 0644 $(XINELPCMPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINELPCMPLUGIN) -endif - -uninstall: -ifeq ($(ENABLE_DEMUX_PLUGIN), yes) - @echo Removing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) -endif -ifeq ($(ENABLE_SPU_PLUGIN), yes) - @echo Removing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) -endif -ifeq ($(ENABLE_INPUT_PLUGIN), yes) - @echo Removing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTPLUGIN) -endif -ifeq ($(ENABLE_PCM_PLUGIN), yes) - @echo Removing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINELPCMPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINELPCMPLUGIN) -endif diff --git a/xine/BluRay/decode_spuhdmv.c b/xine/BluRay/decode_spuhdmv.c deleted file mode 100644 index b210f025..00000000 --- a/xine/BluRay/decode_spuhdmv.c +++ /dev/null @@ -1,1103 +0,0 @@ -/* - * Copyright (C) 2000-2009 the xine project - * - * Copyright (C) 2009 Petri Hintukainen <phintuka@users.sourceforge.net> - * - * This file is part of xine, a unix 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 - * - * Decoder for HDMV/BluRay bitmap subtitles - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <inttypes.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -#ifdef HAVE_CONFIG_H -# include "xine_internal.h" -# include "buffer.h" -# include "xineutils.h" -# include "video_out.h" -# include "video_overlay.h" -#else -# include <xine/xine_internal.h> -# include <xine/buffer.h> -# include <xine/xineutils.h> -# include <xine/video_out.h> -# include <xine/video_overlay.h> -#endif - -#define XINE_HDMV_TRACE(x...) printf(x) -/*#define XINE_HDMV_TRACE(x...) */ -#define XINE_HDMV_ERROR(x...) fprintf(stderr, "spuhdmv: " x) -/*#define XINE_HDMV_ERROR(x...) lprintf(x) */ - -#ifndef EXPORTED -# define EXPORTED __attribute__((visibility("default"))) -#endif - -#ifndef BUF_SPU_HDMV -# define BUF_SPU_HDMV 0x04080000 -#endif - -#ifndef MAX -# define MAX(a,b) (a>b)?(a):(b) -#endif - -enum { - SEGTYPE_PALETTE = 0x14, - SEGTYPE_OBJECT = 0x15, - SEGTYPE_PRESENTATION_SEGMENT = 0x16, - SEGTYPE_WINDOW_DEFINITION = 0x17, - SEGTYPE_INTERACTIVE = 0x18, - SEGTYPE_END_OF_DISPLAY = 0x80, -} eSegmentType; - -/* - * cached palette (xine-lib format) - */ -typedef struct subtitle_clut_s subtitle_clut_t; -struct subtitle_clut_s { - uint8_t id; - uint32_t color[256]; - uint8_t trans[256]; - subtitle_clut_t *next; - - int shown; -}; - -/* - * cached RLE image (xine-lib format) - */ -typedef struct subtitle_object_s subtitle_object_t; -struct subtitle_object_s { - uint16_t id; - uint16_t xpos, ypos; - uint16_t width, height; - - /* xine format */ - rle_elem_t *rle; - unsigned int num_rle; - size_t data_size; - - /* HDMV format (used when object does not fit to single segment) */ - uint32_t data_len; /* size of complete object */ - uint8_t *raw_data; /* partial RLE data in HDMV format */ - size_t raw_data_len; /* bytes buffered */ - size_t raw_data_size; /* allocated size */ - - subtitle_object_t *next; - - int shown; -}; - -/* - * Window definition - */ -typedef struct window_def_s window_def_t; -struct window_def_s { - uint8_t id; - uint16_t xpos, ypos; - uint16_t width, height; - - window_def_t *next; - - int shown; -}; - - -/* - * decoded SPU - */ -typedef struct composition_object_s composition_object_t; -struct composition_object_s { - uint8_t window_id_ref; - uint16_t object_id_ref; - - uint16_t xpos, ypos; - - uint8_t forced_flag; - uint8_t cropped_flag; - uint16_t crop_horiz_pos, crop_vert_pos; - uint16_t crop_width, crop_height; - - composition_object_t *next; - - int shown; -}; - -typedef struct composition_descriptor_s composition_descriptor_t; -struct composition_descriptor_s { - uint16_t number; - uint8_t state; -}; - -typedef struct presentation_segment_s presentation_segment_t; -struct presentation_segment_s { - composition_descriptor_t comp_descr; - - uint8_t palette_update_flag; - uint8_t palette_id_ref; - uint8_t object_number; - - composition_object_t *comp_objs; - - presentation_segment_t *next; - - int64_t pts; - int shown; -}; - -/* - * list handling - */ - -#define LIST_REPLACE(list, obj, FREE_FUNC) \ - do { \ - unsigned int id = obj->id; \ - \ - /* insert to list */ \ - obj->next = list; \ - list = obj; \ - \ - /* remove old */ \ - while (obj->next && obj->next->id != id) \ - obj = obj->next; \ - if (obj->next) { \ - void *tmp = (void*)obj->next; \ - obj->next = obj->next->next; \ - FREE_FUNC(tmp); \ - } \ - } while (0); - -#define LIST_DESTROY(list, FREE_FUNC) \ - while (list) { \ - void *tmp = (void*)list; \ - list = list->next; \ - FREE_FUNC(tmp); \ - } - -static void free_subtitle_object(void *ptr) -{ - if (ptr) { - free(((subtitle_object_t*)ptr)->rle); - free(((subtitle_object_t*)ptr)->raw_data); - free(ptr); - } -} -static void free_presentation_segment(void *ptr) -{ - if (ptr) { - presentation_segment_t *seg = (presentation_segment_t*)ptr; - LIST_DESTROY(seg->comp_objs, free); - free(ptr); - } -} - - -/* - * segment_buffer_t - * - * assemble and decode segments - */ - -typedef struct { - /* current segment */ - int segment_len; /* length of current segment (without 3-byte header) */ - uint8_t segment_type; /* current segment type */ - uint8_t *segment_data; /* pointer to current segment payload */ - uint8_t *segment_end; /* pointer to last byte + 1 of current segment */ - uint8_t error; /* boolean: buffer overflow etc. */ - - /* accumulated data */ - uint8_t *buf; /* */ - size_t len; /* count of unprocessed bytes */ - size_t data_size; /* allocated buffer size */ -} segment_buffer_t; - -/* - * mgmt - */ - -static segment_buffer_t *segbuf_init(void) -{ - segment_buffer_t *buf = calloc(1, sizeof(segment_buffer_t)); - return buf; -} - -static void segbuf_dispose(segment_buffer_t *buf) -{ - if (buf->buf) - free (buf->buf); - free (buf); -} - -static void segbuf_reset(segment_buffer_t *buf) -{ - buf->segment_end = buf->segment_data = buf->buf; - buf->len = 0; - buf->segment_len = -1; - buf->segment_type = 0; - buf->error = 0; -} - -/* - * assemble, parse - */ - -static void segbuf_parse_segment_header(segment_buffer_t *buf) -{ - if (buf->len > 2) { - buf->segment_type = buf->buf[0]; - buf->segment_len = (buf->buf[1] << 8) | buf->buf[2]; - buf->segment_data = buf->buf + 3; - buf->segment_end = buf->segment_data + buf->segment_len; - buf->error = 0; - - if ( buf->segment_type < 0x14 || - ( buf->segment_type > 0x18 && - buf->segment_type != 0x80)) { - XINE_HDMV_ERROR("unknown segment type, resetting\n"); - segbuf_reset(buf); - } - } else { - buf->segment_len = -1; - buf->error = 1; - } -} - -static void segbuf_fill(segment_buffer_t *buf, uint8_t *data, size_t len) -{ - if (buf->len + len > buf->data_size) { - buf->data_size = buf->len + len; - if (buf->buf) - buf->buf = realloc(buf->buf, buf->data_size); - else - buf->buf = malloc(buf->data_size); - } - - memcpy(buf->buf + buf->len, data, len); - buf->len += len; - - segbuf_parse_segment_header(buf); -} - -static int segbuf_segment_complete(segment_buffer_t *buf) -{ - return (buf->segment_len >= 0) && (buf->len >= (unsigned)buf->segment_len + 3); -} - -static void segbuf_skip_segment(segment_buffer_t *buf) -{ - if (segbuf_segment_complete (buf)) { - buf->len -= buf->segment_len + 3; - if (buf->len > 0) - memmove(buf->buf, buf->buf + buf->segment_len + 3, buf->len); - - segbuf_parse_segment_header(buf); - - XINE_HDMV_TRACE(" skip_segment: %zd bytes left\n", buf->len); - } else { - XINE_HDMV_ERROR(" skip_segment: ERROR - %zd bytes queued, %d required\n", - buf->len, buf->segment_len); - segbuf_reset (buf); - } -} - -/* - * access segment data - */ - -static uint8_t segbuf_segment_type(segment_buffer_t *buf) -{ - return buf->segment_type; -} - -static size_t segbuf_data_length(segment_buffer_t *buf) -{ - ssize_t val = buf->segment_end - buf->segment_data; - if (val < 0) val = 0; - return (size_t)val; -} - -static uint8_t segbuf_get_u8(segment_buffer_t *buf) -{ - if (!(buf->error = ++buf->segment_data > buf->segment_end)) - return buf->segment_data[-1]; - XINE_HDMV_ERROR("segbuf_get_u8: read failed (end of segment reached) !\n"); - return 0; -} - -static uint16_t segbuf_get_u16(segment_buffer_t *buf) -{ - return (segbuf_get_u8(buf) << 8) | segbuf_get_u8(buf); -} - -static uint32_t segbuf_get_u24(segment_buffer_t *buf) -{ - return (segbuf_get_u8(buf) << 16) | (segbuf_get_u8(buf) << 8) | segbuf_get_u8(buf); -} - -/* - * decode segments - */ - -static subtitle_clut_t *segbuf_decode_palette(segment_buffer_t *buf) -{ - uint8_t palette_id = segbuf_get_u8 (buf); - uint8_t palette_version_number = segbuf_get_u8 (buf); - - size_t len = segbuf_data_length(buf); - size_t entries = len / 5; - size_t i; - - if (buf->error) - return NULL; - - if (len % 5) { - XINE_HDMV_ERROR(" decode_palette: segment size error (%zd ; expected %zd for %zd entries)\n", - len, (5 * entries), entries); - return NULL; - } - XINE_HDMV_TRACE("decode_palette: %zd items (id %d, version %d)\n", - entries, palette_id, palette_version_number); - - /* convert to xine-lib clut */ - subtitle_clut_t *clut = calloc(1, sizeof(subtitle_clut_t)); - clut->id = palette_id; - - for (i = 0; i < entries; i++) { - uint8_t index = segbuf_get_u8 (buf); - uint8_t Y = segbuf_get_u8 (buf); - uint8_t Cr = segbuf_get_u8 (buf); - uint8_t Cb = segbuf_get_u8 (buf); - uint8_t alpha = segbuf_get_u8 (buf); - clut->color[index] = (Y << 16) | (Cr << 8) | Cb; - clut->trans[index] = alpha >> 4; - } - - return clut; -} - -static int segbuf_decode_rle(segment_buffer_t *buf, subtitle_object_t *obj) -{ - int x = 0, y = 0; - int rle_size = sizeof(rle_elem_t) * obj->width / 16 * obj->height + 1; - rle_elem_t *rlep = malloc(rle_size); - - free (obj->rle); - obj->rle = rlep; - obj->data_size = rle_size; - obj->num_rle = 0; - - /* convert to xine-lib rle format */ - while (y < obj->height && !buf->error) { - - /* decode RLE element */ - uint8_t byte = segbuf_get_u8 (buf); - if (byte != 0) { - rlep->color = byte; - rlep->len = 1; - } else { - byte = segbuf_get_u8 (buf); - if (!(byte & 0x80)) { - rlep->color = 0; - if (!(byte & 0x40)) - rlep->len = byte & 0x3f; - else - rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); - } else { - if (!(byte & 0x40)) - rlep->len = byte & 0x3f; - else - rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); - rlep->color = segbuf_get_u8 (buf); - } - } - - /* move to next element */ - if (rlep->len > 0) { - x += rlep->len; - rlep++; - obj->num_rle ++; - } else { - /* end of line marker (00 00) */ - if (x < obj->width) { - rlep->len = obj->width - x; - rlep->color = 0xff; - rlep++; - obj->num_rle ++; - } - x = 0; - y++; - } - - /* grow allocated RLE data size ? */ - if (obj->data_size <= (obj->num_rle + 1) * sizeof(rle_elem_t)) { - obj->data_size *= 2; - obj->rle = realloc(obj->rle, obj->data_size); - rlep = obj->rle + obj->num_rle; - } - } - - return buf->error; -} - -static subtitle_object_t *segbuf_decode_object(segment_buffer_t *buf, subtitle_object_t *objects) -{ - uint16_t object_id = segbuf_get_u16(buf); - uint8_t version = segbuf_get_u8 (buf); - uint8_t seq_desc = segbuf_get_u8 (buf); - - XINE_HDMV_TRACE(" decode_object: object_id %d, version %d, seq 0x%x\n", - object_id, version, seq_desc); - - if (seq_desc & 0x80) { - /* new object (first-in-sequence flag set) */ - - subtitle_object_t *obj = calloc(1, sizeof(subtitle_object_t)); - - obj->id = object_id; - obj->data_len = segbuf_get_u24(buf); - obj->width = segbuf_get_u16(buf); - obj->height = segbuf_get_u16(buf); - - if (buf->error) { - XINE_HDMV_TRACE(" decode error at object header\n"); - free_subtitle_object(obj); - return NULL; - } - - obj->data_len -= 4; /* width, height parsed */ - - XINE_HDMV_TRACE(" object length %d bytes, size %dx%d\n", obj->data_len, obj->width, obj->height); - - if (obj->data_len > segbuf_data_length(buf)) { - XINE_HDMV_TRACE(" object length %d bytes, have only %zd bytes -> missing %d bytes\n", - obj->data_len, segbuf_data_length(buf), obj->data_len - (int)segbuf_data_length(buf)); - - if (obj->raw_data) - free(obj->raw_data); - - /* store partial RLE data in HDMV format */ - obj->raw_data_len = segbuf_data_length(buf); - obj->raw_data_size = MAX(obj->data_len, obj->raw_data_len); - obj->raw_data = malloc(obj->raw_data_size); - memcpy(obj->raw_data, buf->segment_data, obj->raw_data_len); - - return obj; - } - - segbuf_decode_rle (buf, obj); - - if (buf->error) { - XINE_HDMV_TRACE(" decode error at RLE data\n"); - free_subtitle_object(obj); - return NULL; - } - - return obj; - } - - /* not first-of-sequence --> append data to already existing objct */ - - /* search for object */ - while (objects && objects->id != object_id) - objects = objects->next; - - if (!objects) { - XINE_HDMV_TRACE(" object not found from list, discarding segment\n"); - return NULL; - } - - /* store partial RLE data in HDMV format */ - if (objects->raw_data_size < objects->raw_data_len + segbuf_data_length(buf)) { - XINE_HDMV_ERROR("object larger than object size !\n"); - return NULL; - } - memcpy(objects->raw_data + objects->raw_data_len, buf->segment_data, segbuf_data_length(buf)); - objects->raw_data_len += segbuf_data_length(buf); - - /* if complete, decode RLE data */ - if (objects->raw_data_len >= objects->data_len) { - /* create dummy buffer for segbuf_decode_rle */ - segment_buffer_t tmpbuf = { - .segment_data = objects->raw_data, - .segment_end = objects->raw_data + objects->raw_data_len, - }; - - /* decode RLE data */ - segbuf_decode_rle (&tmpbuf, objects); - - if (tmpbuf.error) { - XINE_HDMV_TRACE(" error decoding multi-segment object\n"); - } - - /* free decode buffer */ - free(objects->raw_data); - objects->raw_data = NULL; - objects->raw_data_len = 0; - objects->raw_data_size = 0; - } - - return NULL; -} - -static window_def_t *segbuf_decode_window_definition(segment_buffer_t *buf) -{ - window_def_t *wnd = calloc(1, sizeof(window_def_t)); - - uint8_t a = segbuf_get_u8 (buf); - wnd->id = segbuf_get_u8 (buf); - wnd->xpos = segbuf_get_u16 (buf); - wnd->ypos = segbuf_get_u16 (buf); - wnd->width = segbuf_get_u16 (buf); - wnd->height = segbuf_get_u16 (buf); - - XINE_HDMV_TRACE(" window: [%02x %d] %d,%d %dx%d\n", a, - wnd->id, wnd->xpos, wnd->ypos, wnd->width, wnd->height); - - if (buf->error) { - free(wnd); - return NULL; - } - - return wnd; -} - -static int segbuf_decode_video_descriptor(segment_buffer_t *buf) -{ - uint16_t width = segbuf_get_u16(buf); - uint16_t height = segbuf_get_u16(buf); - uint8_t frame_rate = segbuf_get_u8 (buf); - - XINE_HDMV_TRACE(" video_descriptor: %dx%d fps %d\n", width, height, frame_rate); - - return buf->error; -} - -static int segbuf_decode_composition_descriptor(segment_buffer_t *buf, composition_descriptor_t *descr) -{ - descr->number = segbuf_get_u16(buf); - descr->state = segbuf_get_u8 (buf) & 0xc0; - - XINE_HDMV_TRACE(" composition_descriptor: number %d, state %d\n", descr->number, descr->state); - return buf->error; -} - -static composition_object_t *segbuf_decode_composition_object(segment_buffer_t *buf) -{ - composition_object_t *cobj = calloc(1, sizeof(composition_object_t)); - - cobj->object_id_ref = segbuf_get_u16 (buf); - cobj->window_id_ref = segbuf_get_u8 (buf); - uint8_t tmp = segbuf_get_u8 (buf); - cobj->cropped_flag = !!(tmp & 0x80); - cobj->forced_flag = !!(tmp & 0x40); - cobj->xpos = segbuf_get_u16 (buf); - cobj->ypos = segbuf_get_u16 (buf); - if (cobj->cropped_flag) { - /* x,y where to take the image from */ - cobj->crop_horiz_pos = segbuf_get_u8 (buf); - cobj->crop_vert_pos = segbuf_get_u8 (buf); - /* size of the cropped image */ - cobj->crop_width = segbuf_get_u8 (buf); - cobj->crop_height = segbuf_get_u8 (buf); - } - - if (buf->error) { - free(cobj); - return NULL; - } - - XINE_HDMV_TRACE(" composition_object: id: %d, win: %d, position %d,%d crop %d forced %d\n", - cobj->object_id_ref, cobj->window_id_ref, cobj->xpos, cobj->ypos, - cobj->cropped_flag, cobj->forced_flag); - - return cobj; -} - -static presentation_segment_t *segbuf_decode_presentation_segment(segment_buffer_t *buf) -{ - presentation_segment_t *seg = calloc(1, sizeof(presentation_segment_t)); - int index; - - segbuf_decode_video_descriptor (buf); - segbuf_decode_composition_descriptor (buf, &seg->comp_descr); - - seg->palette_update_flag = !!((segbuf_get_u8(buf)) & 0x80); - seg->palette_id_ref = segbuf_get_u8 (buf); - seg->object_number = segbuf_get_u8 (buf); - - XINE_HDMV_TRACE(" presentation_segment: object_number %d, palette %d\n", - seg->object_number, seg->palette_id_ref); - - for (index = 0; index < seg->object_number; index++) { - composition_object_t *cobj = segbuf_decode_composition_object (buf); - cobj->next = seg->comp_objs; - seg->comp_objs = cobj; - } - - if (buf->error) { - free_presentation_segment(seg); - return NULL; - } - - return seg; -} - -static rle_elem_t *copy_crop_rle(subtitle_object_t *obj, composition_object_t *cobj) -{ - /* TODO: cropping (w,h sized image from pos x,y) */ - - rle_elem_t *rle = calloc (obj->num_rle, sizeof(rle_elem_t)); - memcpy (rle, obj->rle, obj->num_rle * sizeof(rle_elem_t)); - return rle; -} - - -/* - * xine plugin - */ - -typedef struct { - spu_decoder_class_t decoder_class; -} spuhdmv_class_t; - -typedef struct spuhdmv_decoder_s { - spu_decoder_t spu_decoder; - - spuhdmv_class_t *class; - xine_stream_t *stream; - - segment_buffer_t *buf; - - subtitle_clut_t *cluts; - subtitle_object_t *objects; - window_def_t *windows; - presentation_segment_t *segments; - - int overlay_handles[MAX_OBJECTS]; - - int64_t pts; - -} spuhdmv_decoder_t; - -static void free_objs(spuhdmv_decoder_t *this) -{ - LIST_DESTROY (this->cluts, free); - LIST_DESTROY (this->objects, free_subtitle_object); - LIST_DESTROY (this->windows, free); - LIST_DESTROY (this->segments, free_presentation_segment); -} - -static int decode_palette(spuhdmv_decoder_t *this) -{ - /* decode */ - subtitle_clut_t *clut = segbuf_decode_palette(this->buf); - if (!clut) - return 1; - - LIST_REPLACE (this->cluts, clut, free); - - return 0; -} - -static int decode_object(spuhdmv_decoder_t *this) -{ - /* decode */ - subtitle_object_t *obj = segbuf_decode_object(this->buf, this->objects); - if (!obj) - return 1; - - LIST_REPLACE (this->objects, obj, free_subtitle_object); - - return 0; -} - -static int decode_window_definition(spuhdmv_decoder_t *this) -{ - /* decode */ - window_def_t *wnd = segbuf_decode_window_definition (this->buf); - if (!wnd) - return 1; - - LIST_REPLACE (this->windows, wnd, free); - - return 0; -} - -static int decode_presentation_segment(spuhdmv_decoder_t *this) -{ - /* decode */ - presentation_segment_t *seg = segbuf_decode_presentation_segment(this->buf); - if (!seg) - return 1; - - seg->pts = this->pts; - - /* epoch start or acquistion point -> drop cached objects */ - if (seg->comp_descr.state) { - free_objs(this); - } - - /* replace */ - if (this->segments) - LIST_DESTROY(this->segments, free_presentation_segment); - this->segments = seg; - - return 0; -} - -static int show_overlay(spuhdmv_decoder_t *this, composition_object_t *cobj, unsigned int palette_id_ref, - int overlay_index, int64_t pts, int force_update) -{ - video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager(this->stream->video_out); - metronom_t *metronom = this->stream->metronom; - video_overlay_event_t event = {.vpts = 0}; - vo_overlay_t overlay = {.data_size = 0}; - - /* find palette */ - subtitle_clut_t *clut = this->cluts; - while (clut && clut->id != palette_id_ref) - clut = clut->next; - if (!clut) { - XINE_HDMV_TRACE(" show_overlay: clut %d not found !\n", palette_id_ref); - return -1; - } - - /* find RLE image */ - subtitle_object_t *obj = this->objects; - while (obj && obj->id != cobj->object_id_ref) - obj = obj->next; - if (!obj) { - XINE_HDMV_TRACE(" show_overlay: object %d not found !\n", cobj->object_id_ref); - return -1; - } - if (!obj->rle) { - XINE_HDMV_TRACE(" show_overlay: object %d RLE data not decoded !\n", cobj->object_id_ref); - return -1; - } - - /* find window */ - window_def_t *wnd = this->windows; - while (wnd && wnd->id != cobj->window_id_ref) - wnd = wnd->next; - if (!wnd) { - XINE_HDMV_TRACE(" show_overlay: window %d not found !\n", cobj->window_id_ref); - return -1; - } - - /* do not show again if all elements are unchanged */ - if (!force_update && clut->shown && obj->shown && wnd->shown && cobj->shown) - return 0; - clut->shown = obj->shown = wnd->shown = cobj->shown = 1; - - /* copy palette to xine overlay */ - overlay.rgb_clut = 0; - memcpy(overlay.color, clut->color, sizeof(uint32_t) * 256); - memcpy(overlay.trans, clut->trans, sizeof(uint8_t) * 256); - - /* copy and crop RLE image to xine overlay */ - overlay.width = obj->width; - overlay.height = obj->height; - - overlay.rle = copy_crop_rle (obj, cobj); - overlay.num_rle = obj->num_rle; - overlay.data_size = obj->num_rle * sizeof(rle_elem_t); - - /* */ - - overlay.x = /*wnd->xpos +*/ cobj->xpos; - overlay.y = /*wnd->ypos +*/ cobj->ypos; - - overlay.unscaled = 0; - overlay.hili_top = -1; - overlay.hili_bottom = -1; - overlay.hili_left = -1; - overlay.hili_right = -1; - - XINE_HDMV_TRACE(" -> overlay: %d,%d %dx%d\n", - overlay.x, overlay.y, overlay.width, overlay.height); - - - /* set timings */ - - if (pts > 0) - event.vpts = metronom->got_spu_packet (metronom, pts); - else - event.vpts = 0; - - - /* generate SHOW event */ - - this->stream->video_out->enable_ovl(this->stream->video_out, 1); - - if (this->overlay_handles[overlay_index] < 0) - this->overlay_handles[overlay_index] = ovl_manager->get_handle(ovl_manager, 0); - - event.event_type = OVERLAY_EVENT_SHOW; - event.object.handle = this->overlay_handles[overlay_index]; - event.object.overlay = &overlay; - event.object.object_type = 0; /* subtitle */ - - ovl_manager->add_event (ovl_manager, (void *)&event); - - return 0; -} - -static void hide_overlays(spuhdmv_decoder_t *this, int64_t pts) -{ - video_overlay_event_t event = {.vpts = 0}; - int i = 0; - - while (this->overlay_handles[i] >= 0) { - XINE_HDMV_TRACE(" -> HIDE %d\n", i); - - video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager(this->stream->video_out); - metronom_t *metronom = this->stream->metronom; - - event.object.handle = this->overlay_handles[i]; - if (this) - event.vpts = metronom->got_spu_packet (metronom, pts); - else - event.vpts = 0; - event.event_type = OVERLAY_EVENT_HIDE; - event.object.overlay = NULL; - ovl_manager->add_event (ovl_manager, (void *)&event); - - //this->overlay_handles[i] = -1; - i++; - } -} - -static void update_overlays(spuhdmv_decoder_t *this) -{ - presentation_segment_t *pseg = this->segments; - - while (pseg) { - - if (!pseg->object_number) { - - /* HIDE */ - if (!pseg->shown) - hide_overlays (this, pseg->pts); - - } else { - - /* SHOW */ - composition_object_t *cobj = pseg->comp_objs; - int i; - - for (i = 0; i < pseg->object_number; i++) { - if (!cobj) { - XINE_HDMV_ERROR("show_overlays: composition object %d missing !\n", i); - } else { - show_overlay(this, cobj, pseg->palette_id_ref, i, pseg->pts, !pseg->shown); - cobj = cobj->next; - } - } - } - - pseg->shown = 1; - - pseg = pseg->next; - } -} - -static void decode_segment(spuhdmv_decoder_t *this) -{ - XINE_HDMV_TRACE("*** new segment, pts %010"PRId64": 0x%02x (%8d bytes)\n", - this->pts, this->buf->segment_type, this->buf->segment_len); - - switch (segbuf_segment_type(this->buf)) { - case SEGTYPE_PALETTE: - XINE_HDMV_TRACE(" segment: PALETTE\n"); - decode_palette(this); - break; - case SEGTYPE_OBJECT: - XINE_HDMV_TRACE(" segment: OBJECT\n"); - decode_object(this); - break; - case SEGTYPE_PRESENTATION_SEGMENT: - XINE_HDMV_TRACE(" segment: PRESENTATION SEGMENT\n"); - decode_presentation_segment(this); - break; - case SEGTYPE_WINDOW_DEFINITION: - XINE_HDMV_TRACE(" segment: WINDOW DEFINITION\n"); - decode_window_definition(this); - break; - case SEGTYPE_INTERACTIVE: - XINE_HDMV_TRACE(" segment: INTERACTIVE\n"); - break; - case SEGTYPE_END_OF_DISPLAY: - XINE_HDMV_TRACE(" segment: END OF DISPLAY\n"); -#if 0 - /* drop all cached objects */ - free_objs(this); -#endif - break; - default: - XINE_HDMV_ERROR(" segment type 0x%x unknown, skipping\n", segbuf_segment_type(this->buf)); - break; - } - if (this->buf->error) { - XINE_HDMV_ERROR("*** DECODE ERROR ***\n"); - } - - update_overlays (this); -} - -static void close_osd(spuhdmv_decoder_t *this) -{ - video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager (this->stream->video_out); - - int i = 0; - while (this->overlay_handles[i] >= 0) { - ovl_manager->free_handle(ovl_manager, this->overlay_handles[i]); - this->overlay_handles[i] = -1; - i++; - } -} - -static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf) -{ - spuhdmv_decoder_t *this = (spuhdmv_decoder_t *) this_gen; - - if ((buf->type & 0xffff0000) != BUF_SPU_HDMV) - return; - - if (buf->size < 1) - return; - - if (buf->pts) - this->pts = buf->pts; - -#ifdef DUMP_SPU_DATA - int i; - for(i = 0; i < buf->size; i++) - printf(" %02x", buf->content[i]); - printf("\n"); -#endif - - segbuf_fill(this->buf, buf->content, buf->size); - - while (segbuf_segment_complete(this->buf)) { - decode_segment(this); - segbuf_skip_segment(this->buf); - } -} - -static void spudec_reset (spu_decoder_t * this_gen) -{ - spuhdmv_decoder_t *this = (spuhdmv_decoder_t *) this_gen; - - if (this->buf) - segbuf_reset(this->buf); - - free_objs(this); - - close_osd(this); -} - -static void spudec_discontinuity (spu_decoder_t *this_gen) -{ - spuhdmv_decoder_t *this = (spuhdmv_decoder_t *) this_gen; - - close_osd(this); -} - -static void spudec_dispose (spu_decoder_t *this_gen) -{ - spuhdmv_decoder_t *this = (spuhdmv_decoder_t *) this_gen; - - close_osd (this); - segbuf_dispose (this->buf); - - free_objs(this); - - free (this); -} - -static spu_decoder_t *open_plugin (spu_decoder_class_t *class_gen, xine_stream_t *stream) -{ - spuhdmv_decoder_t *this; - - this = (spuhdmv_decoder_t *) calloc(1, sizeof (spuhdmv_decoder_t)); - - this->spu_decoder.decode_data = spudec_decode_data; - this->spu_decoder.reset = spudec_reset; - this->spu_decoder.discontinuity = spudec_discontinuity; - this->spu_decoder.dispose = spudec_dispose; - this->spu_decoder.get_interact_info = NULL; - this->spu_decoder.set_button = NULL; - this->stream = stream; - this->class = (spuhdmv_class_t *) class_gen; - - this->buf = segbuf_init(); - - memset(this->overlay_handles, 0xff, sizeof(this->overlay_handles)); /* --> -1 */ - - return &this->spu_decoder; -} - -static char *get_identifier (spu_decoder_class_t *this) -{ - return "spuhdmv"; -} - -static char *get_description (spu_decoder_class_t *this) -{ - return "HDMV/BluRay bitmap SPU decoder plugin"; -} - -static void dispose_class (spu_decoder_class_t *this) -{ - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) -{ - spuhdmv_class_t *this; - - this = calloc(1, sizeof (spuhdmv_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; - - return this; -} - -/* plugin catalog information */ -static uint32_t supported_types[] = { BUF_SPU_HDMV, 0 }; - -static const decoder_info_t dec_info_data = { - supported_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_SPU_DECODER, 16, "spuhdmv", XINE_VERSION_CODE, &dec_info_data, &init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/xine/BluRay/demux_ts.c b/xine/BluRay/demux_ts.c deleted file mode 100644 index 9b78005f..00000000 --- a/xine/BluRay/demux_ts.c +++ /dev/null @@ -1,2783 +0,0 @@ - -/* - * Copyright (C) 2000-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * Demultiplexer for MPEG2 Transport Streams. - * - * For the purposes of playing video, we make some assumptions about the - * kinds of TS we have to process. The most important simplification is to - * assume that the TS contains a single program (SPTS) because this then - * allows significant simplifications to be made in processing PATs. - * - * The next simplification is to assume that the program has a reasonable - * number of video, audio and other streams. This allows PMT processing to - * be simplified. - * - * MODIFICATION HISTORY - * - * Date Author - * ---- ------ - * - * 8-Apr-2009 Petri Hintukainen <phi@sdf-eu.org> - * - support for 192-byte packets (HDMV/BluRay) - * - support for audio inside PES PID 0xfd (HDMV/BluRay) - * - demux HDMV/BluRay bitmap subtitles - * - * 28-Nov-2004 Mike Lampard <mlampard> - * - Added support for PMT sections larger than 1 ts packet - * - * 28-Aug-2004 James Courtier-Dutton <jcdutton> - * - Improve PAT and PMT handling. Added some FIXME comments. - * - * 9-Aug-2003 James Courtier-Dutton <jcdutton> - * - Improve readability of code. Added some FIXME comments. - * - * 25-Nov-2002 Peter Liljenberg - * - Added DVBSUB support - * - * 07-Nov-2992 Howdy Pierce - * - various bugfixes - * - * 30-May-2002 Mauro Borghi - * - dynamic allocation leaks fixes - * - * 27-May-2002 Giovanni Baronetti and Mauro Borghi <mauro.borghi@tilab.com> - * - fill buffers before putting them in fifos - * - force PMT reparsing when PMT PID changes - * - accept non seekable input plugins -- FIX? - * - accept dvb as input plugin - * - optimised read operations - * - modified resync code - * - * 16-May-2002 Thibaut Mattern <tmattern@noos.fr> - * - fix demux loop - * - * 07-Jan-2002 Andr Draszik <andid@gmx.net> - * - added support for single-section PMTs - * spanning multiple TS packets - * - * 10-Sep-2001 James Courtier-Dutton <jcdutton> - * - re-wrote sync code so that it now does not loose any data - * - * 27-Aug-2001 Hubert Matthews Reviewed by: n/a - * - added in synchronisation code - * - * 1-Aug-2001 James Courtier-Dutton <jcdutton> Reviewed by: n/a - * - TS Streams with zero PES length should now work - * - * 30-Jul-2001 shaheedhaque Reviewed by: n/a - * - PATs and PMTs seem to work - * - * 29-Jul-2001 shaheedhaque Reviewed by: n/a - * - Compiles! - * - * - * TODO: do without memcpys, preview buffers - */ - - -/** HOW TO IMPLEMENT A DVBSUB DECODER. - * - * The DVBSUB protocol is specified in ETSI EN 300 743. It can be - * downloaded for free (registration required, though) from - * www.etsi.org. - * - * The spu_decoder should handle the packet type BUF_SPU_DVB. - * - * BUF_SPU_DVBSUB packets without the flag BUF_FLAG_SPECIAL contain - * the payload of the PES packets carrying DVBSUB data. Since the - * payload can be broken up over several buf_element_t and the DVBSUB - * is PES oriented, the decoder_info[2] field (low 16 bits) is used to convey the - * packet boundaries to the decoder: - * - * + For the first buffer of a packet, buf->content points to the - * first byte of the PES payload. decoder_info[2] is set to the length of the - * payload. The decoder can use this value to determine when a - * complete PES packet has been collected. - * - * + For the following buffers of the PES packet, decoder_info[2] is 0. - * - * The decoder can either use this information to reconstruct the PES - * payload, or ignore it and implement a parser that handles the - * irregularites at the start and end of PES packets. - * - * In any case buf->pts is always set to the PTS of the PES packet. - * - * - * BUF_SPU_DVB with BUF_FLAG_SPECIAL set contains no payload, and is - * used to pass control information to the decoder. - * - * If decoder_info[1] == BUF_SPECIAL_SPU_DVB_DESCRIPTOR then - * decoder_info_ptr[2] either points to a spu_dvb_descriptor_t or is NULL. - * - * If it is 0, the user has disabled the subtitling, or has selected a - * channel that is not present in the stream. The decoder should - * remove any visible subtitling. - * - * If it is a pointer, the decoder should reset itself and start - * extracting the subtitle service identified by comp_page_id and - * aux_page_id in the spu_dvb_descriptor_t, (the composition and - * auxilliary page ids, respectively). - **/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> - -#define LOG_MODULE "demux_ts" -#define LOG_VERBOSE -/* -#define LOG -*/ - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/demux.h> - -//#define TS_PMT_LOG -//#define TS_PAT_LOG - -#ifndef EXPORTED -# define EXPORTED __attribute__((visibility("default"))) -#endif - -#ifndef BUF_SPU_HDMV -# define BUF_SPU_HDMV 0x04080000 -#endif -#ifndef BUF_AUDIO_AAC_LATM -# define BUF_AUDIO_AAC_LATM 0x03420000 -#endif -#ifndef XINE_EVENT_END_OF_CLIP -# define XINE_EVENT_END_OF_CLIP 0x80000001 -#endif - -/* - #define TS_LOG - #define TS_PMT_LOG - #define TS_PAT_LOG - - #define TS_READ_STATS // activates read statistics generation - #define TS_HEADER_LOG // prints out the Transport packet header. -*/ - -/* - * The maximum number of PIDs we are prepared to handle in a single program - * is the number that fits in a single-packet PMT. - */ -#define PKT_SIZE 188 -#define BODY_SIZE (188 - 4) -/* more PIDS are needed due "auto-detection". 40 spare media entries */ -#define MAX_PIDS ((BODY_SIZE - 1 - 13) / 4) + 40 -#define MAX_PMTS ((BODY_SIZE - 1 - 13) / 4) + 10 -#define SYNC_BYTE 0x47 - -#define MIN_SYNCS 3 -#define NPKT_PER_READ 96 // 96*188 = 94*192 - -#define BUF_SIZE (NPKT_PER_READ * (PKT_SIZE + 4)) - -#define MAX_PES_BUF_SIZE 2048 - -#define CORRUPT_PES_THRESHOLD 10 - -#define NULL_PID 0x1fff -#define INVALID_PID ((unsigned int)(-1)) -#define INVALID_PROGRAM ((unsigned int)(-1)) -#define INVALID_CC ((unsigned int)(-1)) - -#define PROG_STREAM_MAP 0xBC -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -/* descriptors in PMT stream info */ -#define DESCRIPTOR_REG_FORMAT 0x05 -#define DESCRIPTOR_LANG 0x0a -#define DESCRIPTOR_TELETEXT 0x56 -#define DESCRIPTOR_DVBSUB 0x59 -#define DESCRIPTOR_AC3 0x6a -#define DESCRIPTOR_EAC3 0x7a -#define DESCRIPTOR_DTS 0x7b -#define DESCRIPTOR_AAC 0x7c - - typedef enum - { - ISO_11172_VIDEO = 0x01, /* ISO/IEC 11172 Video */ - ISO_13818_VIDEO = 0x02, /* ISO/IEC 13818-2 Video */ - ISO_11172_AUDIO = 0x03, /* ISO/IEC 11172 Audio */ - ISO_13818_AUDIO = 0x04, /* ISO/IEC 13818-3 Audi */ - ISO_13818_PRIVATE = 0x05, /* ISO/IEC 13818-1 private sections */ - ISO_13818_PES_PRIVATE = 0x06, /* ISO/IEC 13818-1 PES packets containing private data */ - ISO_13522_MHEG = 0x07, /* ISO/IEC 13512 MHEG */ - ISO_13818_DSMCC = 0x08, /* ISO/IEC 13818-1 Annex A DSM CC */ - ISO_13818_TYPE_A = 0x0a, /* ISO/IEC 13818-6 Multiprotocol encapsulation */ - ISO_13818_TYPE_B = 0x0b, /* ISO/IEC 13818-6 DSM-CC U-N Messages */ - ISO_13818_TYPE_C = 0x0c, /* ISO/IEC 13818-6 Stream Descriptors */ - ISO_13818_TYPE_D = 0x0d, /* ISO/IEC 13818-6 Sections (any type, including private data) */ - ISO_13818_AUX = 0x0e, /* ISO/IEC 13818-1 auxiliary */ - ISO_13818_PART7_AUDIO = 0x0f, /* ISO/IEC 13818-7 Audio with ADTS transport sytax */ - ISO_14496_PART2_VIDEO = 0x10, /* ISO/IEC 14496-2 Visual (MPEG-4) */ - ISO_14496_PART3_AUDIO = 0x11, /* ISO/IEC 14496-3 Audio with LATM transport syntax */ - ISO_14496_PART10_VIDEO = 0x1b, /* ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) */ - STREAM_VIDEO_MPEG = 0x80, - STREAM_AUDIO_AC3 = 0x81, - - STREAM_VIDEO_VC1 = 0xea, /* VC-1 Video */ - STREAM_VIDEO_SMTPE_VC1 = 0xeb, /* SMTPE VC-1 */ - - HDMV_AUDIO_80_PCM = 0x80, /* BluRay PCM */ - HDMV_AUDIO_82_DTS = 0x82, /* DTS */ - HDMV_AUDIO_83_TRUEHD = 0x83, /* Dolby TrueHD, primary audio */ - HDMV_AUDIO_84_EAC3 = 0x84, /* Dolby Digital plus, primary audio */ - HDMV_AUDIO_85_DTS_HRA = 0x85, /* DTS-HRA */ - HDMV_AUDIO_86_DTS_HD_MA = 0x86, /* DTS-HD Master audio */ - - HDMV_SPU_BITMAP = 0x90, - HDMV_SPU_INTERACTIVE = 0x91, - HDMV_SPU_TEXT = 0x92, - - } streamType; - -#define WRAP_THRESHOLD 270000 - -#define PTS_AUDIO 0 -#define PTS_VIDEO 1 - -/* bitrate estimation */ -#define TBRE_MIN_TIME ( 2 * 90000) -#define TBRE_TIME (480 * 90000) - -#define TBRE_MODE_PROBE 0 -#define TBRE_MODE_AUDIO_PTS 1 -#define TBRE_MODE_AUDIO_PCR 2 -#define TBRE_MODE_PCR 3 -#define TBRE_MODE_DONE 4 - - -#undef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) -#undef MAX -#define MAX(a,b) ((a)>(b)?(a):(b)) - -/* -** -** DATA STRUCTURES -** -*/ - -/* - * Describe a single elementary stream. - */ -typedef struct { - unsigned int pid; - fifo_buffer_t *fifo; - uint8_t *content; - uint32_t size; - uint32_t type; - int64_t pts; - buf_element_t *buf; - unsigned int counter; - uint16_t descriptor_tag; /* +0x100 for PES stream IDs (no available TS descriptor tag?) */ - int corrupted_pes; - - int input_normpos; - int input_time; -} demux_ts_media; - -/* DVBSUB */ -#define MAX_SPU_LANGS 32 - -typedef struct { - spu_dvb_descriptor_t desc; - unsigned int pid; - int media_index; -} demux_ts_spu_lang; - -/* Audio Channels */ -#define MAX_AUDIO_TRACKS 32 - -typedef struct { - unsigned int pid; - int media_index; - char lang[4]; -} demux_ts_audio_track; - -typedef struct { - /* - * The first field must be the "base class" for the plugin! - */ - demux_plugin_t demux_plugin; - - xine_stream_t *stream; - - config_values_t *config; - - fifo_buffer_t *audio_fifo; - fifo_buffer_t *video_fifo; - - input_plugin_t *input; - - int status; - - int hdmv; /* -1 = unknown, 0 = mpeg-ts, 1 = hdmv/m2ts */ - int pkt_size; /* TS packet size */ - int pkt_offset; /* TS packet offset */ - - int rate; - unsigned int media_num; - demux_ts_media media[MAX_PIDS]; - - /* PAT */ - uint32_t last_pat_crc; - uint32_t transport_stream_id; - /* programs */ - uint32_t program_number[MAX_PMTS]; - uint32_t pmt_pid[MAX_PMTS]; - uint8_t *pmt[MAX_PMTS]; - uint8_t *pmt_write_ptr[MAX_PMTS]; - uint32_t crc32_table[256]; - uint32_t last_pmt_crc; - /* - * Stuff to do with the transport header. As well as the video - * and audio PIDs, we keep the index of the corresponding entry - * inthe media[] array. - */ - unsigned int pcr_pid; - unsigned int videoPid; - unsigned int videoMedia; - - demux_ts_audio_track audio_tracks[MAX_AUDIO_TRACKS]; - int audio_tracks_count; - - int64_t last_pts[2]; - int send_newpts; - int buf_flag_seek; - - unsigned int scrambled_pids[MAX_PIDS]; - unsigned int scrambled_npids; - -#ifdef TS_READ_STATS - uint32_t rstat[NPKT_PER_READ + 1]; -#endif - - /* DVBSUB */ - unsigned int spu_pid; - unsigned int spu_media; - demux_ts_spu_lang spu_langs[MAX_SPU_LANGS]; - int spu_langs_count; - int current_spu_channel; - - /* dvb */ - xine_event_queue_t *event_queue; - /* For syncronisation */ - int32_t packet_number; - /* NEW: var to keep track of number of last read packets */ - int32_t npkt_read; - - uint8_t buf[BUF_SIZE]; /* == PKT_SIZE * NPKT_PER_READ */ - - off_t frame_pos; /* current ts packet position in input stream (bytes from beginning) */ - - /* bitrate estimation */ - off_t tbre_bytes, tbre_lastpos; - int64_t tbre_time, tbre_lasttime; - unsigned int tbre_mode, tbre_pid; - -} demux_ts_t; - -typedef struct { - - demux_class_t demux_class; - - /* class-wide, global variables here */ - - xine_t *xine; - config_values_t *config; -} demux_ts_class_t; - -static void demux_ts_tbre_reset (demux_ts_t *this) { - if (this->tbre_time <= TBRE_TIME) { - this->tbre_pid = INVALID_PID; - this->tbre_mode = TBRE_MODE_PROBE; - } -} - -static void demux_ts_tbre_update (demux_ts_t *this, unsigned int mode, int64_t now) { - /* select best available timesource on the fly */ - if ((mode < this->tbre_mode) || (now <= 0)) - return; - - if (mode == this->tbre_mode) { - /* skip discontinuities */ - int64_t diff = now - this->tbre_lasttime; - if ((diff < 0 ? -diff : diff) < 220000) { - /* add this step */ - this->tbre_bytes += this->frame_pos - this->tbre_lastpos; - this->tbre_time += diff; - /* update bitrate */ - if (this->tbre_time > TBRE_MIN_TIME) - this->rate = this->tbre_bytes * 90000 / this->tbre_time; - /* stop analyzing */ - if (this->tbre_time > TBRE_TIME) - this->tbre_mode = TBRE_MODE_DONE; - } - } else { - /* upgrade timesource */ - this->tbre_mode = mode; - } - - /* remember where and when */ - this->tbre_lastpos = this->frame_pos; - this->tbre_lasttime = now; -} - -static void demux_ts_build_crc32_table(demux_ts_t*this) { - uint32_t i, j, k; - - for( i = 0 ; i < 256 ; i++ ) { - k = 0; - for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { - k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); - } - this->crc32_table[i] = k; - } -} - -static uint32_t demux_ts_compute_crc32(demux_ts_t*this, uint8_t *data, - int32_t length, uint32_t crc32) { - int32_t i; - - for(i = 0; i < length; i++) { - crc32 = (crc32 << 8) ^ this->crc32_table[(crc32 >> 24) ^ data[i]]; - } - return crc32; -} - -/* redefine abs as macro to handle 64-bit diffs. - i guess llabs may not be available everywhere */ -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - -static void check_newpts( demux_ts_t *this, int64_t pts, int video ) -{ - int64_t diff; - -#ifdef TS_LOG - printf ("demux_ts: check_newpts %lld, send_newpts %d, buf_flag_seek %d\n", - pts, this->send_newpts, this->buf_flag_seek); -#endif - - diff = pts - this->last_pts[video]; - - if( pts && - (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { - - if (this->buf_flag_seek) { - _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); - this->buf_flag_seek = 0; - } else { - _x_demux_control_newpts(this->stream, pts, 0); - } - this->send_newpts = 0; - this->last_pts[1-video] = 0; - } - - if( pts ) - { - /* don't detect a discontinuity only for video respectively audio. It's also a discontinuity - indication when audio and video pts differ to much e. g. when a pts wrap happens. - The original code worked well when the wrap happend like this: - - V7 A7 V8 V9 A9 Dv V0 V1 da A1 V2 V3 A3 V4 - - Legend: - Vn = video packet with timestamp n - An = audio packet with timestamp n - Dv = discontinuity detected on following video packet - Da = discontinuity detected on following audio packet - dv = discontinuity detected on following video packet but ignored - da = discontinuity detected on following audio packet but ignored - - But with a certain delay between audio and video packets (e. g. the way DVB-S broadcasts - the packets) the code didn't work: - - V7 V8 A7 V9 Dv V0 _A9_ V1 V2 Da _A1_ V3 V4 A3 - - Packet A9 caused audio to jump forward and A1 caused it to jump backward with inserting - a delay of almoust 26.5 hours! - - The new code gives the following sequences for the above examples: - - V7 A7 V8 V9 A9 Dv V0 V1 A1 V2 V3 A3 V4 - - V7 V8 A7 V9 Dv V0 Da A9 Dv V1 V2 A1 V3 V4 A3 - - After proving this code it should be cleaned up to use just a single variable "last_pts". */ - -/* - this->last_pts[video] = pts; -*/ - this->last_pts[video] = this->last_pts[1-video] = pts; - } -} - -/* Send a BUF_SPU_DVB to let xine know of that channel. */ -static void demux_send_special_spu_buf( demux_ts_t *this, uint32_t spu_type, int spu_channel ) -{ - buf_element_t *buf; - - buf = this->video_fifo->buffer_pool_alloc( this->video_fifo ); - buf->type = spu_type|spu_channel; - buf->content = buf->mem; - buf->size = 0; - this->video_fifo->put( this->video_fifo, buf ); -} - -static void demux_send_special_audio_buf( demux_ts_t *this, uint16_t stream_type, int audio_channel ) -{ - uint32_t type = 0; - - switch(stream_type) { - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: type = BUF_AUDIO_MPEG; break; - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: type = BUF_AUDIO_AAC; break; - default: - case STREAM_AUDIO_AC3: type = BUF_AUDIO_A52; break; - } - - if (this->hdmv > 0) { - switch(stream_type) { - case HDMV_AUDIO_80_PCM: type = BUF_AUDIO_LPCM_BE; break; - case HDMV_AUDIO_83_TRUEHD: - case STREAM_AUDIO_AC3: type = BUF_AUDIO_A52; break; - case HDMV_AUDIO_82_DTS: - case HDMV_AUDIO_85_DTS_HRA: - case HDMV_AUDIO_86_DTS_HD_MA: type = BUF_AUDIO_DTS; break; - } - } - - if (type && this->audio_fifo) { - buf_element_t *buf = this->audio_fifo->buffer_pool_alloc( this->audio_fifo ); - buf->type = type | audio_channel; - buf->decoder_flags = BUF_FLAG_PREVIEW; - buf->content = buf->mem; - buf->size = 0; - this->audio_fifo->put( this->audio_fifo, buf ); - } -} - -/* - * demux_ts_update_spu_channel - * - * Send a BUF_SPU_DVB with BUF_SPECIAL_SPU_DVB_DESCRIPTOR to tell - * the decoder to reset itself on the new channel. - */ -static void demux_ts_update_spu_channel(demux_ts_t *this) -{ - buf_element_t *buf; - - this->current_spu_channel = this->stream->spu_channel; - - buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - buf->type = BUF_SPU_DVB; - buf->content = buf->mem; - buf->decoder_flags = BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR; - buf->size = 0; - - if (this->current_spu_channel >= 0 - && this->current_spu_channel < this->spu_langs_count) - { - demux_ts_spu_lang *lang = &this->spu_langs[this->current_spu_channel]; - - buf->decoder_info[2] = sizeof(lang->desc); - buf->decoder_info_ptr[2] = &(lang->desc); - buf->type |= this->current_spu_channel; - - this->spu_pid = lang->pid; - this->spu_media = lang->media_index; - -#ifdef TS_LOG - printf("demux_ts: DVBSUB: selecting lang: %s page %ld %ld\n", - lang->desc.lang, lang->desc.comp_page_id, lang->desc.aux_page_id); -#endif - } - else - { - buf->decoder_info_ptr[2] = NULL; - - this->spu_pid = INVALID_PID; - -#ifdef TS_LOG - printf("demux_ts: DVBSUB: deselecting lang\n"); -#endif - } - - if ((this->media[this->spu_media].type & BUF_MAJOR_MASK) == BUF_SPU_HDMV) { - buf->type = BUF_SPU_HDMV; - } - - this->video_fifo->put(this->video_fifo, buf); -} - -static void demux_ts_send_buffer(demux_ts_media *m, int flags) -{ - if (m->buf) { - m->buf->content = m->buf->mem; - m->buf->type = m->type; - m->buf->decoder_flags |= flags; - m->buf->pts = m->pts; - m->buf->decoder_info[0] = 1; - m->buf->extra_info->input_normpos = m->input_normpos; - m->buf->extra_info->input_time = m->input_time; - - m->fifo->put(m->fifo, m->buf); - m->buf = NULL; - -#ifdef TS_LOG - printf ("demux_ts: produced buffer, pts=%lld\n", m->pts); -#endif - } -} - -static void demux_ts_flush_media(demux_ts_media *m) -{ - demux_ts_send_buffer(m, BUF_FLAG_FRAME_END); -} - -static void demux_ts_flush(demux_ts_t *this) -{ - unsigned int i; - for (i = 0; i < this->media_num; ++i) { - demux_ts_flush_media(&this->media[i]); - } -} - -/* - * demux_ts_parse_pat - * - * Parse a program association table (PAT). - * The PAT is expected to be exactly one section long, - * and that section is expected to be contained in a single TS packet. - * - * The PAT is assumed to contain a single program definition, though - * we can cope with the stupidity of SPTSs which contain NITs. - */ -static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, - unsigned char *pkt, unsigned int pusi) { - uint32_t table_id; - uint32_t section_syntax_indicator; - int32_t section_length; - uint32_t transport_stream_id; - uint32_t version_number; - uint32_t current_next_indicator; - uint32_t section_number; - uint32_t last_section_number; - uint32_t crc32; - uint32_t calc_crc32; - - unsigned char *program; - unsigned int program_number; - unsigned int pmt_pid; - unsigned int program_count; - - /* - * A PAT in a single section should start with a payload unit start - * indicator set. - */ - if (!pusi) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PAT without payload unit start indicator\n"); - return; - } - - /* - * sections start with a pointer. Skip it! - */ - pkt += pkt[4]; - if (pkt - original_pkt > PKT_SIZE) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PAT with invalid pointer\n"); - return; - } - table_id = (unsigned int)pkt[5] ; - section_syntax_indicator = (((unsigned int)pkt[6] >> 7) & 1) ; - section_length = (((unsigned int)pkt[6] & 0x03) << 8) | pkt[7]; - transport_stream_id = ((uint32_t)pkt[8] << 8) | pkt[9]; - version_number = ((uint32_t)pkt[10] >> 1) & 0x1f; - current_next_indicator = ((uint32_t)pkt[10] & 0x01); - section_number = (uint32_t)pkt[11]; - last_section_number = (uint32_t)pkt[12]; - crc32 = (uint32_t)pkt[4+section_length] << 24; - crc32 |= (uint32_t)pkt[5+section_length] << 16; - crc32 |= (uint32_t)pkt[6+section_length] << 8; - crc32 |= (uint32_t)pkt[7+section_length] ; - -#ifdef TS_PAT_LOG - printf ("demux_ts: PAT table_id: %.2x\n", table_id); - printf (" section_syntax: %d\n", section_syntax_indicator); - printf (" section_length: %d (%#.3x)\n", - section_length, section_length); - printf (" transport_stream_id: %#.4x\n", transport_stream_id); - printf (" version_number: %d\n", version_number); - printf (" c/n indicator: %d\n", current_next_indicator); - printf (" section_number: %d\n", section_number); - printf (" last_section_number: %d\n", last_section_number); -#endif - - if ((section_syntax_indicator != 1) || !(current_next_indicator)) { - return; - } - - if (pkt - original_pkt > BODY_SIZE - 1 - 3 - section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: FIXME: (unsupported )PAT spans multiple TS packets\n"); - return; - } - - if ((section_number != 0) || (last_section_number != 0)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: FIXME: (unsupported) PAT consists of multiple (%d) sections\n", last_section_number); - return; - } - - /* Check CRC. */ - calc_crc32 = demux_ts_compute_crc32 (this, pkt+5, section_length+3-4, - 0xffffffff); - if (crc32 != calc_crc32) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PAT with invalid CRC32: packet_crc32: %.8x calc_crc32: %.8x\n", - crc32,calc_crc32); - return; - } -#ifdef TS_PAT_LOG - else { - printf ("demux_ts: PAT CRC32 ok.\n"); - } -#endif - - if (crc32 == this->last_pat_crc && - this->transport_stream_id == transport_stream_id) { - lprintf("demux_ts: PAT CRC unchanged\n"); - return; - } - - if (this->transport_stream_id != transport_stream_id) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: PAT transport_stream_id changed\n"); - } - - this->last_pat_crc = crc32; - this->transport_stream_id = transport_stream_id; - - /* - * Process all programs in the program loop. - */ - program_count = 0; - for (program = pkt + 13; - (program < pkt + 13 + section_length - 9) && (program_count < MAX_PMTS); - program += 4) { - program_number = ((unsigned int)program[0] << 8) | program[1]; - pmt_pid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; - - /* - * completely skip NIT pids. - */ - if (program_number == 0x0000) - continue; - - /* - * Add the program number to the table if we haven't already - * seen it. The order of the program numbers is assumed not - * to change between otherwise identical PATs. - */ - if (this->program_number[program_count] != program_number) { - this->program_number[program_count] = program_number; - this->pmt_pid[program_count] = INVALID_PID; - } - - /* force PMT reparsing when pmt_pid changes */ - if (this->pmt_pid[program_count] != pmt_pid) { - this->pmt_pid[program_count] = pmt_pid; - this->audio_tracks_count = 0; - this->last_pmt_crc = 0; - this->videoPid = INVALID_PID; - this->spu_pid = INVALID_PID; - this->pcr_pid = INVALID_PID; - - if (this->pmt[program_count] != NULL) { - free(this->pmt[program_count]); - this->pmt[program_count] = NULL; - this->pmt_write_ptr[program_count] = NULL; - } - } -#ifdef TS_PAT_LOG - if (this->program_number[program_count] != INVALID_PROGRAM) - printf ("demux_ts: PAT acquired count=%d programNumber=0x%04x " - "pmtPid=0x%04x\n", - program_count, - this->program_number[program_count], - this->pmt_pid[program_count]); -#endif - - ++program_count; - } - - /* Add "end of table" markers. */ - if (program_count < MAX_PMTS) { - this->program_number[program_count] = INVALID_PROGRAM; - this->pmt_pid[program_count] = INVALID_PID; - } -} - -static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, - uint8_t *buf, int packet_len) { - - unsigned char *p; - int header_len; - int64_t pts; - uint32_t stream_id; - - if (packet_len < 9) { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: too short PES packet header (%d bytes)\n", packet_len); - return 0; - } - - p = buf; - - /* we should have a PES packet here */ - - if (p[0] || p[1] || (p[2] != 1)) { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: error %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); - return 0 ; - } - - /* packet_len = p[4] << 8 | p[5]; */ - stream_id = p[3]; - header_len = p[8]; - - /* sometimes corruption on header_len causes segfault in memcpy below */ - if (header_len + 9 > packet_len) { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len); - return 0; - } - -#ifdef TS_LOG - printf ("demux_ts: packet stream id: %.2x len: %d (%x)\n", - stream_id, packet_len, packet_len); -#endif - - if (p[7] & 0x80) { /* pts avail */ - - if (header_len < 5) { - return 0; - } - - pts = (int64_t)(p[ 9] & 0x0E) << 29 ; - pts |= p[10] << 22 ; - pts |= (p[11] & 0xFE) << 14 ; - pts |= p[12] << 7 ; - pts |= (p[13] & 0xFE) >> 1 ; - - } else - pts = 0; - - /* code works but not used in xine - if (p[7] & 0x40) { - - DTS = (p[14] & 0x0E) << 29 ; - DTS |= p[15] << 22 ; - DTS |= (p[16] & 0xFE) << 14 ; - DTS |= p[17] << 7 ; - DTS |= (p[18] & 0xFE) >> 1 ; - - } else - DTS = 0; - */ - - m->pts = pts; - - p += header_len + 9; - packet_len -= header_len + 9; - - if (m->descriptor_tag == STREAM_VIDEO_VC1) { - m->content = p; - m->size = packet_len; - m->type = BUF_VIDEO_VC1; - return 1; - } - - if (m->descriptor_tag == HDMV_SPU_BITMAP) { - long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; - - m->content = p; - m->size = packet_len; - m->type |= BUF_SPU_HDMV; - m->buf->decoder_info[2] = payload_len; - return 1; - - } else - - if (stream_id == 0xbd || stream_id == 0xfd /* HDMV */) { - - int spu_id; - - lprintf ("audio buf = %02X %02X %02X %02X %02X %02X %02X %02X\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - - /* - * we check the descriptor tag first because some stations - * do not include any of the ac3 header info in their audio tracks - * these "raw" streams may begin with a byte that looks like a stream type. - * For audio streams, m->type already contains the stream no. - */ - if(m->descriptor_tag == HDMV_AUDIO_84_EAC3) { - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_EAC3; - return 1; - - } else if (m->descriptor_tag == STREAM_AUDIO_AC3) { /* ac3 - raw */ - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_A52; - return 1; - - } else if (m->descriptor_tag == HDMV_AUDIO_83_TRUEHD) { - /* TODO: separate AC3 and TrueHD streams ... */ - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_A52; - return 1; - - } else if (m->descriptor_tag == HDMV_AUDIO_82_DTS || - m->descriptor_tag == HDMV_AUDIO_85_DTS_HRA || - m->descriptor_tag == HDMV_AUDIO_86_DTS_HD_MA ) { - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_DTS; - return 1; - - } else if (packet_len < 2) { - return 0; - - } else if (m->descriptor_tag == HDMV_AUDIO_80_PCM) { - - if (packet_len < 4) { - return 0; - } - - m->content = p + 4; - m->size = packet_len - 4; - m->type |= BUF_AUDIO_LPCM_BE; - - m->buf->decoder_flags |= BUF_FLAG_SPECIAL; - m->buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; - m->buf->decoder_info[2] = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0]; - - return 1; - - } else if (m->descriptor_tag == ISO_13818_PES_PRIVATE - && p[0] == 0x20 && p[1] == 0x00) { - /* DVBSUB */ - long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; - - m->content = p; - m->size = packet_len; - m->type |= BUF_SPU_DVB; - m->buf->decoder_info[2] = payload_len; - return 1; - - } else if (p[0] == 0x0B && p[1] == 0x77) { /* ac3 - syncword */ - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_A52; - return 1; - - } else if ((p[0] & 0xE0) == 0x20) { - spu_id = (p[0] & 0x1f); - - m->content = p+1; - m->size = packet_len-1; - m->type = BUF_SPU_DVD + spu_id; - return 1; - } else if ((p[0] & 0xF0) == 0x80) { - - if (packet_len < 4) { - return 0; - } - - m->content = p+4; - m->size = packet_len - 4; - m->type |= BUF_AUDIO_A52; - return 1; - -#if 0 - /* commented out: does not set PCM type. Decoder can't handle raw PCM stream without configuration. */ - } else if ((p[0]&0xf0) == 0xa0) { - - unsigned int pcm_offset; - - for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ){ - if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ - pcm_offset += 2; - break; - } - } - - if (packet_len < pcm_offset) { - return 0; - } - - m->content = p+pcm_offset; - m->size = packet_len-pcm_offset; - m->type |= BUF_AUDIO_LPCM_BE; - return 1; -#endif - } - - } else if ((stream_id & 0xf0) == 0xe0) { - - m->content = p; - m->size = packet_len; - switch (m->descriptor_tag) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case STREAM_VIDEO_MPEG: - lprintf ("demux_ts: found MPEG video type.\n"); - m->type = BUF_VIDEO_MPEG; - break; - case ISO_14496_PART2_VIDEO: - lprintf ("demux_ts: found MPEG4 video type.\n"); - m->type = BUF_VIDEO_MPEG4; - break; - case ISO_14496_PART10_VIDEO: - lprintf ("demux_ts: found H264 video type.\n"); - m->type = BUF_VIDEO_H264; - break; - default: - lprintf ("demux_ts: unknown video type: %d, defaulting to MPEG.\n", m->descriptor_tag); - m->type = BUF_VIDEO_MPEG; - break; - } - return 1; - - } else if ((stream_id & 0xe0) == 0xc0) { - - m->content = p; - m->size = packet_len; - switch (m->descriptor_tag) { - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - lprintf ("demux_ts: found MPEG audio track.\n"); - m->type |= BUF_AUDIO_MPEG; - break; - case ISO_13818_PART7_AUDIO: - lprintf ("demux_ts: found AAC audio track.\n"); - m->type |= BUF_AUDIO_AAC; - break; - case ISO_14496_PART3_AUDIO: - lprintf ("demux_ts: found AAC LATM audio track.\n"); - m->type |= BUF_AUDIO_AAC_LATM; - break; - default: - lprintf ("demux_ts: unknown audio type: %d, defaulting to MPEG.\n", m->descriptor_tag); - m->type |= BUF_AUDIO_MPEG; - break; - } - return 1; - - } else { -#ifdef TS_LOG - printf ("demux_ts: unknown packet, id: %x\n", stream_id); -#endif - } - - return 0 ; -} - - -static void fill_extra_info(demux_ts_t *this, buf_element_t *buf) -{ - off_t len = this->input->get_length (this->input); - off_t pos = this->input->get_current_pos (this->input); - - if (len) { - buf->extra_info->input_normpos = (int)( (double) pos * 65535 / len ); - } - - if (this->input->get_current_time) - buf->extra_info->input_time = this->input->get_current_time(this->input); - - if (this->rate) { - if (buf->extra_info->input_time <= 0) - buf->extra_info->input_time = (int)((int64_t)pos * 1000 / this->rate); - - buf->extra_info->total_time = (int)((int64_t)len * 1000 / this->rate); - } -} - -/* - * buffer arriving pes data - */ -static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, - unsigned int mediaIndex, - unsigned int pus, - unsigned int cc, - unsigned int len) { - - demux_ts_media *m = &this->media[mediaIndex]; - - if (!m->fifo) { -#ifdef TS_LOG - printf ("fifo unavailable (%d)\n", mediaIndex); -#endif - return; /* To avoid segfault if video out or audio out plugin not loaded */ - } - - /* By checking the CC here, we avoid the need to check for the no-payload - case (i.e. adaptation field only) when it does not get bumped. */ - if (m->counter != INVALID_CC) { - if ((m->counter & 0x0f) != cc) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: PID 0x%.4x: unexpected cc %d (expected %d)\n", m->pid, cc, m->counter); - } - } - m->counter = cc; - m->counter++; - - if (pus) { /* new PES packet */ - - demux_ts_flush_media(m); - - /* allocate the buffer here, as pes_header needs a valid buf for dvbsubs */ - m->buf = m->fifo->buffer_pool_alloc(m->fifo); - - if (!demux_ts_parse_pes_header(this->stream->xine, m, ts, len)) { - m->buf->free_buffer(m->buf); - m->buf = NULL; - - m->corrupted_pes++; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: PID 0x%.4x: corrupted pes encountered\n", m->pid); - } else { - - m->corrupted_pes = 0; - memcpy(m->buf->mem, ts+len-m->size, m->size); - m->buf->size = m->size; - - /* cache frame position */ - off_t length = this->input->get_length (this->input); - if (length > 0) { - m->input_normpos = (double)this->frame_pos * 65535.0 / length; - } - if (this->rate) { - m->input_time = this->frame_pos * 1000 / this->rate; - } - - /* rate estimation */ - if ((this->tbre_pid == INVALID_PID) && (this->audio_fifo == m->fifo)) - this->tbre_pid = m->pid; - if (m->pid == this->tbre_pid) - demux_ts_tbre_update (this, TBRE_MODE_AUDIO_PTS, m->pts); - } - - } else if (!m->corrupted_pes) { /* no pus -- PES packet continuation */ - - if ((m->buf->size + len) > MAX_PES_BUF_SIZE) { - demux_ts_send_buffer(m, 0); - m->buf = m->fifo->buffer_pool_alloc(m->fifo); - } - memcpy(m->buf->mem + m->buf->size, ts, len); - m->buf->size += len; - } -} - -/* - * Create a buffer for a PES stream. - */ -static void demux_ts_pes_new(demux_ts_t*this, - unsigned int mediaIndex, - unsigned int pid, - fifo_buffer_t *fifo, - uint16_t descriptor) { - - demux_ts_media *m = &this->media[mediaIndex]; - - /* new PID seen - initialise stuff */ - m->pid = pid; - m->fifo = fifo; - - if (m->buf != NULL) m->buf->free_buffer(m->buf); - m->buf = NULL; - m->counter = INVALID_CC; - m->descriptor_tag = descriptor; - m->corrupted_pes = 1; -} - - -/* Find the first ISO 639 language descriptor (tag 10) and - * store the 3-char code in dest, nullterminated. If no - * code is found, zero out dest. - **/ -static void demux_ts_get_lang_desc(demux_ts_t *this, char *dest, - const unsigned char *data, int length) -{ - const unsigned char *d = data; - - while (d < (data + length)) - - { - if (d[0] == DESCRIPTOR_LANG && d[1] >= 4) - - { - memcpy(dest, d + 2, 3); - dest[3] = 0; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: found ISO 639 lang: %s\n", dest); - return; - } - d += 2 + d[1]; - } - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: found no ISO 639 lang\n"); - memset(dest, 0, 4); -} - -/* Find the registration code (tag=5) and return it as a uint32_t - * This should return "AC-3" or 0x41432d33 for AC3/A52 audio tracks. - */ -static void demux_ts_get_reg_desc(demux_ts_t *this, uint32_t *dest, - const unsigned char *data, int length) -{ - const unsigned char *d = data; - - while (d < (data + length)) - - { - if (d[0] == DESCRIPTOR_REG_FORMAT && d[1] >= 4) - - { - *dest = (d[2] << 24) | (d[3] << 16) | (d[4] << 8) | d[5]; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: found registration format identifier: 0x%.4x\n", *dest); - return; - } - d += 2 + d[1]; - } - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: found no format id\n"); - *dest = 0; -} - -static inline int ts_payloadsize(unsigned char * tsp) -{ - if (!(tsp[3] & 0x10)) - return 0; - if (tsp[3] & 0x20) { - if (tsp[4] > 183) - return 0; - else - return 183 - tsp[4]; - } - return 184; -} - -/* check if an apid is in the list of known apids */ -static int apid_check(demux_ts_t*this, unsigned int pid) { - int i; - for (i = 0; i < this->audio_tracks_count; i++) { - if (this->audio_tracks[i].pid == pid) - return i; - } - return -1; -} - -/* - * NAME demux_ts_parse_pmt - * - * Parse a PMT. The PMT is expected to be exactly one section long, - * and that section is expected to be contained in a single TS packet. - * - * In other words, the PMT is assumed to describe a reasonable number of - * video, audio and other streams (with descriptors). - * FIXME: Implement support for multi section PMT. - */ -static void demux_ts_parse_pmt (demux_ts_t *this, - unsigned char *originalPkt, - unsigned char *pkt, - unsigned int pusi, - uint32_t program_count) { - - uint32_t table_id; - uint32_t section_syntax_indicator; - uint32_t section_length = 0; /* to calm down gcc */ - uint32_t program_number; - uint32_t version_number; - uint32_t current_next_indicator; - uint32_t section_number; - uint32_t last_section_number; - uint32_t program_info_length; - uint32_t crc32; - uint32_t calc_crc32; - uint32_t coded_length; - unsigned int pid; - unsigned char *stream; - unsigned int i; - int count; - char *ptr = NULL; - unsigned char len; - unsigned int offset=0; - - /* - * A new section should start with the payload unit start - * indicator set. We allocate some mem (max. allowed for a PM section) - * to copy the complete section into one chunk. - */ - if (pusi) { - pkt+=pkt[4]; /* pointer to start of section */ - offset=1; - - free(this->pmt[program_count]); - this->pmt[program_count] = (uint8_t *) calloc(4096, sizeof(unsigned char)); - this->pmt_write_ptr[program_count] = this->pmt[program_count]; - - table_id = pkt[5] ; - section_syntax_indicator = (pkt[6] >> 7) & 0x01; - section_length = (((uint32_t) pkt[6] << 8) | pkt[7]) & 0x03ff; - program_number = ((uint32_t) pkt[8] << 8) | pkt[9]; - version_number = (pkt[10] >> 1) & 0x1f; - current_next_indicator = pkt[10] & 0x01; - section_number = pkt[11]; - last_section_number = pkt[12]; - -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT table_id: %2x\n", table_id); - printf (" section_syntax: %d\n", section_syntax_indicator); - printf (" section_length: %d (%#.3x)\n", - section_length, section_length); - printf (" program_number: %#.4x\n", program_number); - printf (" version_number: %d\n", version_number); - printf (" c/n indicator: %d\n", current_next_indicator); - printf (" section_number: %d\n", section_number); - printf (" last_section_number: %d\n", last_section_number); -#endif - - if ((section_syntax_indicator != 1) || !current_next_indicator) { -#ifdef TS_PMT_LOG - printf ("ts_demux: section_syntax_indicator != 1 " - "|| !current_next_indicator\n"); -#endif - return; - } - - if (program_number != this->program_number[program_count]) { - /* several programs can share the same PMT pid */ -#ifdef TS_PMT_LOG -printf("Program Number is %i, looking for %i\n",program_number,this->program_number[program_count]); - printf ("ts_demux: waiting for next PMT on this PID...\n"); -#endif - return; - } - - if ((section_number != 0) || (last_section_number != 0)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: FIXME (unsupported) PMT consists of multiple (%d) sections\n", last_section_number); - return; - } - - } - - if (!this->pmt[program_count]) { - /* not the first TS packet of a PMT, or the calloc didn't work */ -#ifdef TS_PMT_LOG - printf ("ts_demux: not the first TS packet of a PMT...\n"); -#endif - return; - } - - if (!pusi){ - section_length = (this->pmt[program_count][1] << 8 - | this->pmt[program_count][2]) & 0x03ff; - } - - count=ts_payloadsize(originalPkt); - - ptr = (char*)originalPkt+offset+(PKT_SIZE-count); - len = count-offset; - memcpy (this->pmt_write_ptr[program_count], ptr, len); - this->pmt_write_ptr[program_count] +=len; - -#ifdef TS_PMT_LOG - printf ("ts_demux: wr_ptr: %p, will be %p when finished\n", - this->pmt_write_ptr[program_count], - this->pmt[program_count] + section_length); -#endif - if (this->pmt_write_ptr[program_count] < this->pmt[program_count] - + section_length) { - /* didn't get all TS packets for this section yet */ -#ifdef TS_PMT_LOG - printf ("ts_demux: didn't get all PMT TS packets yet...\n"); -#endif - return; - } - - if (!section_length) { - free (this->pmt[program_count]); - this->pmt[program_count] = NULL; -#ifdef TS_PMT_LOG - printf ("ts_demux: eek, zero-length section?\n"); -#endif - return; - } - -#ifdef TS_PMT_LOG - printf ("ts_demux: have all TS packets for the PMT section\n"); -#endif - - crc32 = (uint32_t) this->pmt[program_count][section_length+3-4] << 24; - crc32 |= (uint32_t) this->pmt[program_count][section_length+3-3] << 16; - crc32 |= (uint32_t) this->pmt[program_count][section_length+3-2] << 8; - crc32 |= (uint32_t) this->pmt[program_count][section_length+3-1] ; - - /* Check CRC. */ - calc_crc32 = demux_ts_compute_crc32 (this, - this->pmt[program_count], - section_length+3-4, 0xffffffff); - if (crc32 != calc_crc32) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PMT with invalid CRC32: packet_crc32: %#.8x calc_crc32: %#.8x\n", - crc32,calc_crc32); - return; - } - else { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT CRC32 ok.\n"); -#endif - if ( crc32==this->last_pmt_crc ) { -#ifdef TS_PMT_LOG - printf("demux_ts: PMT with CRC32=%d already parsed. Skipping.\n", crc32); -#endif - return; - } - else { -#ifdef TS_PMT_LOG - printf("demux_ts: new PMT, parsing...\n"); -#endif - this->last_pmt_crc = crc32; - } - } - - /* - * Forget the current video, audio and subtitle PIDs; if the PMT has not - * changed, we'll pick them up again when we parse this PMT, while if the - * PMT has changed (e.g. an IPTV streamer that's just changed its source), - * we'll get new PIDs that we should follow. - */ - this->audio_tracks_count = 0; - this->videoPid = INVALID_PID; - this->spu_pid = INVALID_PID; - - /* - * ES definitions start here...we are going to learn upto one video - * PID and one audio PID. - */ - program_info_length = ((this->pmt[program_count][10] << 8) - | this->pmt[program_count][11]) & 0x0fff; - -/* Program info descriptor is currently just ignored. - * printf ("demux_ts: program_info_desc: "); - * for (i = 0; i < program_info_length; i++) - * printf ("%.2x ", this->pmt[program_count][12+i]); - * printf ("\n"); - */ - stream = &this->pmt[program_count][12] + program_info_length; - coded_length = 13 + program_info_length; - if (coded_length > section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux error! PMT with inconsistent progInfo length\n"); - return; - } - section_length -= coded_length; - - /* - * Extract the elementary streams. - */ - this->spu_langs_count = 0; - while (section_length > 0) { - unsigned int stream_info_length; - - pid = ((stream[1] << 8) | stream[2]) & 0x1fff; - stream_info_length = ((stream[3] << 8) | stream[4]) & 0x0fff; - coded_length = 5 + stream_info_length; - if (coded_length > section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux error! PMT with inconsistent streamInfo length\n"); - return; - } - - /* - * Squirrel away the first audio and the first video stream. TBD: there - * should really be a way to select the stream of interest. - */ - switch (stream[0]) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case ISO_14496_PART2_VIDEO: - case ISO_14496_PART10_VIDEO: - case STREAM_VIDEO_VC1: - if (this->videoPid == INVALID_PID) { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT video pid 0x%.4x type %2.2x\n", pid, stream[0]); -#endif - demux_ts_pes_new(this, this->media_num, pid, this->video_fifo,stream[0]); - this->videoMedia = this->media_num; - this->videoPid = pid; - } - - break; - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - if (this->audio_tracks_count < MAX_AUDIO_TRACKS) { - if (apid_check(this, pid) < 0) { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]); -#endif - demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo,stream[0]); - this->audio_tracks[this->audio_tracks_count].pid = pid; - this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; - this->media[this->media_num].type = this->audio_tracks_count; - demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang, - stream + 5, stream_info_length); - demux_send_special_audio_buf(this, stream[0], this->audio_tracks_count); - this->audio_tracks_count++; - } - } - break; - case ISO_13818_PRIVATE: -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT streamtype 13818_PRIVATE, pid: 0x%.4x type %2.2x\n", pid, stream[0]); - - for (i = 5; i < coded_length; i++) - printf ("%.2x ", stream[i]); - printf ("\n"); -#endif - break; - case ISO_13818_TYPE_C: /* data carousel */ -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT streamtype 13818_TYPE_C, pid: 0x%.4x type %2.2x\n", pid, stream[0]); -#endif - break; - case ISO_13818_PES_PRIVATE: - for (i = 5; i < coded_length; i += stream[i+1] + 2) { - if (((stream[i] == DESCRIPTOR_AC3) || (stream[i] == DESCRIPTOR_EAC3)) && - (this->audio_tracks_count < MAX_AUDIO_TRACKS)) { - if (apid_check(this, pid) < 0) { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT AC3 audio pid 0x%.4x type %2.2x\n", pid, stream[0]); -#endif - if (stream[i] == DESCRIPTOR_AC3) - demux_ts_pes_new(this, this->media_num, pid, - this->audio_fifo, STREAM_AUDIO_AC3); - else - demux_ts_pes_new(this, this->media_num, pid, - this->audio_fifo, HDMV_AUDIO_84_EAC3); - - this->audio_tracks[this->audio_tracks_count].pid = pid; - this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; - this->media[this->media_num].type = this->audio_tracks_count; - demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang, - stream + 5, stream_info_length); - demux_send_special_audio_buf(this, STREAM_AUDIO_AC3, this->audio_tracks_count); - this->audio_tracks_count++; - break; - } - } - /* Teletext */ - else if (stream[i] == DESCRIPTOR_TELETEXT) - { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT Teletext, pid: 0x%.4x type %2.2x\n", pid, stream[0]); - - for (i = 5; i < coded_length; i++) - printf ("%.2x ", stream[i]); - printf ("\n"); -#endif - break; - } - - /* DVBSUB */ - else if (stream[i] == DESCRIPTOR_DVBSUB) - { - unsigned int pos; - for (pos = i + 2; - pos + 8 <= i + 2 + stream[i + 1] - && this->spu_langs_count < MAX_SPU_LANGS; - pos += 8) - { - int no = this->spu_langs_count; - demux_ts_spu_lang *lang = &this->spu_langs[no]; - - this->spu_langs_count++; - - memcpy(lang->desc.lang, &stream[pos], 3); - lang->desc.lang[3] = 0; - lang->desc.comp_page_id = - (stream[pos + 4] << 8) | stream[pos + 5]; - lang->desc.aux_page_id = - (stream[pos + 6] << 8) | stream[pos + 7]; - lang->pid = pid; - lang->media_index = this->media_num; - this->media[this->media_num].type = no; - demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]); - demux_send_special_spu_buf( this, BUF_SPU_DVB, no ); -#ifdef TS_LOG - printf("demux_ts: DVBSUB: pid 0x%.4x: %s page %ld %ld type %2.2x\n", - pid, lang->desc.lang, - lang->desc.comp_page_id, - lang->desc.aux_page_id, - stream[0]); -#endif - } - } - } - break; - - case HDMV_SPU_INTERACTIVE: - case HDMV_SPU_TEXT: - if (this->hdmv > 0) { - printf("demux_ts: Skipping unsupported HDMV subtitle stream_type: 0x%.2x pid: 0x%.4x\n", - stream[0], pid); - break; - } - /* fall thru */ - - case HDMV_SPU_BITMAP: - if (this->hdmv > 0) { - if (pid >= 0x1200 && pid < 0x1300) { - /* HDMV Presentation Graphics / SPU */ - - if (this->spu_langs_count >= MAX_SPU_LANGS) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: too many SPU tracks! ignoring pid 0x%.4x\n", - pid); - break; - } - - demux_ts_spu_lang *lang = &this->spu_langs[this->spu_langs_count]; - - memset(lang->desc.lang, 0, sizeof(lang->desc.lang)); - /*memcpy(lang->desc.lang, &stream[pos], 3);*/ - /*lang->desc.lang[3] = 0;*/ - lang->pid = pid; - lang->media_index = this->media_num; - this->media[this->media_num].type = this->spu_langs_count; - demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]); - demux_send_special_spu_buf( this, BUF_SPU_HDMV, this->spu_langs_count ); - this->spu_langs_count++; -#ifdef TS_PMT_LOG - printf("demux_ts: HDMV subtitle stream_type: 0x%.2x pid: 0x%.4x\n", - stream[0], pid); -#endif - break; - } - } - /* fall thru */ - default: - -/* This following section handles all the cases where the audio track info is stored in PMT user info with stream id >= 0x80 - * We first check that the stream id >= 0x80, because all values below that are invalid if not handled above, - * then we check the registration format identifier to see if it holds "AC-3" (0x41432d33) and - * if is does, we tag this as an audio stream. - * FIXME: This will need expanding if we ever see a DTS or other media format here. - */ - if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { - if (apid_check(this,pid) < 0) { - uint32_t format_identifier=0; - demux_ts_get_reg_desc(this, &format_identifier, - stream + 5, stream_info_length); - /* If no format identifier, assume A52 */ - if (( format_identifier == 0x41432d33) || - ( format_identifier == 0) || - ((format_identifier == 0x48444d56 || this->hdmv>0) && stream[0] == HDMV_AUDIO_80_PCM) /* BluRay PCM */) { - - demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo, stream[0]); - this->audio_tracks[this->audio_tracks_count].pid = pid; - this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; - this->media[this->media_num].type = this->audio_tracks_count; - demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang, - stream + 5, stream_info_length); - demux_send_special_audio_buf(this, stream[0], this->audio_tracks_count); - this->audio_tracks_count++; - break; - } - } - } else { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT unknown stream_type: 0x%.2x pid: 0x%.4x\n", - stream[0], pid); - - for (i = 5; i < coded_length; i++) - printf ("%.2x ", stream[i]); - printf ("\n"); -#endif - } - break; - } - this->media_num++; - stream += coded_length; - section_length -= coded_length; - } - - /* - * Get the current PCR PID. - */ - pid = ((this->pmt[program_count][8] << 8) - | this->pmt[program_count][9]) & 0x1fff; - if (this->pcr_pid != pid) { -#ifdef TS_PMT_LOG - if (this->pcr_pid == INVALID_PID) { - printf ("demux_ts: PMT pcr pid 0x%.4x\n", pid); - } else { - printf ("demux_ts: PMT pcr pid changed 0x%.4x\n", pid); - } -#endif - this->pcr_pid = pid; - } - - if ( this->stream->spu_channel>=0 && this->spu_langs_count>0 ) - demux_ts_update_spu_channel( this ); - - demux_ts_tbre_reset (this); - - /* Inform UI of channels changes */ - xine_event_t ui_event; - ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED; - ui_event.data_length = 0; - xine_event_send( this->stream, &ui_event ); -} - -static int sync_correct(demux_ts_t*this, uint8_t *buf, int32_t npkt_read) { - - int p = 0; - int n = 0; - int i = 0; - int sync_ok = 0; - int read_length; - - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: about to resync!\n"); - - for (p=0; p < npkt_read; p++) { - for(n=0; n < this->pkt_size; n++) { - sync_ok = 1; - for (i=0; i < MIN(MIN_SYNCS, npkt_read - p); i++) { - if (buf[this->pkt_offset + n + ((i+p) * this->pkt_size)] != SYNC_BYTE) { - sync_ok = 0; - break; - } - } - if (sync_ok) break; - } - if (sync_ok) break; - } - - if (sync_ok) { - /* Found sync, fill in */ - memmove(&buf[0], &buf[n + p * this->pkt_size], - ((this->pkt_size * (npkt_read - p)) - n)); - read_length = this->input->read(this->input, - (char*)&buf[(this->pkt_size * (npkt_read - p)) - n], - n + p * this->pkt_size); - /* FIXME: when read_length is not as required... we now stop demuxing */ - if (read_length != (n + p * this->pkt_size)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts_tsync_correct: sync found, but read failed\n"); - return 0; - } - } else { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts_tsync_correct: sync not found! Stop demuxing\n"); - return 0; - } - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: resync successful!\n"); - return 1; -} - -static int sync_detect(demux_ts_t*this, uint8_t *buf, int32_t npkt_read) { - - int i, sync_ok; - - sync_ok = 1; - - if (this->hdmv) { - this->pkt_size = PKT_SIZE + 4; - this->pkt_offset = 4; - for (i=0; i < MIN(MIN_SYNCS, npkt_read - 3); i++) { - if (buf[this->pkt_offset + i * this->pkt_size] != SYNC_BYTE) { - sync_ok = 0; - break; - } - } - if (sync_ok) { - if (this->hdmv < 0) { - /* fix npkt_read (packet size is 192, not 188) */ - this->npkt_read = npkt_read * PKT_SIZE / this->pkt_size; - } - this->hdmv = 1; - return sync_ok; - } - if (this->hdmv > 0) - return sync_correct(this, buf, npkt_read); - - /* plain ts */ - this->hdmv = 0; - this->pkt_size = PKT_SIZE; - this->pkt_offset = 0; - } - - for (i=0; i < MIN(MIN_SYNCS, npkt_read); i++) { - if (buf[i * PKT_SIZE] != SYNC_BYTE) { - sync_ok = 0; - break; - } - } - if (!sync_ok) return sync_correct(this, buf, npkt_read); - return sync_ok; -} - - -/* - * Main synchronisation routine. - */ -static unsigned char * demux_synchronise(demux_ts_t* this) { - - uint8_t *return_pointer = NULL; - int32_t read_length; - - this->frame_pos += this->pkt_size; - - if ( (this->packet_number) >= this->npkt_read) { - - /* NEW: handle read returning less packets than NPKT_PER_READ... */ - do { - this->frame_pos = this->input->get_current_pos (this->input); - - read_length = this->input->read(this->input, (char*)this->buf, - this->pkt_size * NPKT_PER_READ); - if (read_length < 0 || read_length % this->pkt_size) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: read returned %d bytes (not a multiple of %d!)\n", - read_length, this->pkt_size); - this->status = DEMUX_FINISHED; - return NULL; - } - this->npkt_read = read_length / this->pkt_size; - -#ifdef TS_READ_STATS - this->rstat[this->npkt_read]++; -#endif - /* - * what if this->npkt_read < 5 ? --> ok in sync_detect - * - * NEW: stop demuxing if read returns 0 a few times... (200) - */ - - if (this->npkt_read == 0) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: read 0 packets\n"); - this->status = DEMUX_FINISHED; - return NULL; - } - - } while (! read_length); - - this->packet_number = 0; - - if (!sync_detect(this, &(this->buf)[0], this->npkt_read)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: sync error.\n"); - this->status = DEMUX_FINISHED; - return NULL; - } - } - return_pointer = &(this->buf)[this->pkt_offset + this->pkt_size * this->packet_number]; - this->packet_number++; - return return_pointer; -} - - -static int64_t demux_ts_adaptation_field_parse(uint8_t *data, - uint32_t adaptation_field_length) { - -#ifdef TS_LOG - uint32_t discontinuity_indicator=0; - uint32_t random_access_indicator=0; - uint32_t elementary_stream_priority_indicator=0; -#endif - uint32_t PCR_flag=0; - int64_t PCR=-1; -#ifdef TS_LOG - uint32_t EPCR=0; - uint32_t OPCR_flag=0; - uint32_t OPCR=0; - uint32_t EOPCR=0; - uint32_t slicing_point_flag=0; - uint32_t transport_private_data_flag=0; - uint32_t adaptation_field_extension_flag=0; -#endif - uint32_t offset = 1; - -#ifdef TS_LOG - discontinuity_indicator = ((data[0] >> 7) & 0x01); - random_access_indicator = ((data[0] >> 6) & 0x01); - elementary_stream_priority_indicator = ((data[0] >> 5) & 0x01); -#endif - PCR_flag = ((data[0] >> 4) & 0x01); -#ifdef TS_LOG - OPCR_flag = ((data[0] >> 3) & 0x01); - slicing_point_flag = ((data[0] >> 2) & 0x01); - transport_private_data_flag = ((data[0] >> 1) & 0x01); - adaptation_field_extension_flag = (data[0] & 0x01); -#endif - -#ifdef TS_LOG - printf ("demux_ts: ADAPTATION FIELD length: %d (%x)\n", - adaptation_field_length, adaptation_field_length); - if(discontinuity_indicator) { - printf (" Discontinuity indicator: %d\n", - discontinuity_indicator); - } - if(random_access_indicator) { - printf (" Random_access indicator: %d\n", - random_access_indicator); - } - if(elementary_stream_priority_indicator) { - printf (" Elementary_stream_priority_indicator: %d\n", - elementary_stream_priority_indicator); - } -#endif - - if(PCR_flag) { - if (adaptation_field_length < offset + 6) - return -1; - - PCR = (((int64_t) data[offset]) & 0xFF) << 25; - PCR += (int64_t) ((data[offset+1] & 0xFF) << 17); - PCR += (int64_t) ((data[offset+2] & 0xFF) << 9); - PCR += (int64_t) ((data[offset+3] & 0xFF) << 1); - PCR += (int64_t) ((data[offset+4] & 0x80) >> 7); - -#ifdef TS_LOG - EPCR = ((data[offset+4] & 0x1) << 8) | data[offset+5]; - printf ("demux_ts: PCR: %lld, EPCR: %u\n", - PCR, EPCR); -#endif - offset+=6; - } - -#ifdef TS_LOG - if(OPCR_flag) { - if (adaptation_field_length < offset + 6) - return PCR; - - OPCR = data[offset] << 25; - OPCR |= data[offset+1] << 17; - OPCR |= data[offset+2] << 9; - OPCR |= data[offset+3] << 1; - OPCR |= (data[offset+4] >> 7) & 0x01; - EOPCR = ((data[offset+4] & 0x1) << 8) | data[offset+5]; - - printf ("demux_ts: OPCR: %u, EOPCR: %u\n", - OPCR,EOPCR); - - offset+=6; - } - - if(slicing_point_flag) { - printf ("demux_ts: slicing_point_flag: %d\n", - slicing_point_flag); - } - if(transport_private_data_flag) { - printf ("demux_ts: transport_private_data_flag: %d\n", - transport_private_data_flag); - } - if(adaptation_field_extension_flag) { - printf ("demux_ts: adaptation_field_extension_flag: %d\n", - adaptation_field_extension_flag); - } -#endif /* TS_LOG */ - - return PCR; -} - -/* transport stream packet layer */ -static void demux_ts_parse_packet (demux_ts_t*this) { - - unsigned char *originalPkt; - unsigned int sync_byte; - unsigned int transport_error_indicator; - unsigned int payload_unit_start_indicator; - unsigned int transport_priority; - unsigned int pid; - unsigned int transport_scrambling_control; - unsigned int adaptation_field_control; - unsigned int continuity_counter; - unsigned int data_offset; - unsigned int data_len; - uint32_t program_count; - unsigned int i; - - /* get next synchronised packet, or NULL */ - originalPkt = demux_synchronise(this); - if (originalPkt == NULL) - return; - - sync_byte = originalPkt[0]; - transport_error_indicator = (originalPkt[1] >> 7) & 0x01; - payload_unit_start_indicator = (originalPkt[1] >> 6) & 0x01; - transport_priority = (originalPkt[1] >> 5) & 0x01; - pid = ((originalPkt[1] << 8) | - originalPkt[2]) & 0x1fff; - transport_scrambling_control = (originalPkt[3] >> 6) & 0x03; - adaptation_field_control = (originalPkt[3] >> 4) & 0x03; - continuity_counter = originalPkt[3] & 0x0f; - - -#ifdef TS_HEADER_LOG - printf("demux_ts:ts_header:sync_byte=0x%.2x\n",sync_byte); - printf("demux_ts:ts_header:transport_error_indicator=%d\n", transport_error_indicator); - printf("demux_ts:ts_header:payload_unit_start_indicator=%d\n", payload_unit_start_indicator); - printf("demux_ts:ts_header:transport_priority=%d\n", transport_priority); - printf("demux_ts:ts_header:pid=0x%.4x\n", pid); - printf("demux_ts:ts_header:transport_scrambling_control=0x%.1x\n", transport_scrambling_control); - printf("demux_ts:ts_header:adaptation_field_control=0x%.1x\n", adaptation_field_control); - printf("demux_ts:ts_header:continuity_counter=0x%.1x\n", continuity_counter); -#endif - /* - * Discard packets that are obviously bad. - */ - if (sync_byte != SYNC_BYTE) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux error! invalid ts sync byte %.2x\n", sync_byte); - return; - } - if (transport_error_indicator) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux error! transport error\n"); - return; - } - if (pid == 0x1ffb) { - /* printf ("demux_ts: PSIP table. Program Guide etc....not supported yet. PID = 0x1ffb\n"); */ - return; - } - - if (transport_scrambling_control) { - if (this->videoPid == pid) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: selected videoPid is scrambled; skipping...\n"); - } - for (i=0; i < this->scrambled_npids; i++) { - if (this->scrambled_pids[i] == pid) return; - } - if (this->scrambled_npids < MAX_PIDS) { - this->scrambled_pids[this->scrambled_npids] = pid; - this->scrambled_npids++; - } - - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: PID 0x%.4x is scrambled!\n", pid); - return; - } - - data_offset = 4; - - if( adaptation_field_control & 0x2 ){ - uint32_t adaptation_field_length = originalPkt[4]; - if (adaptation_field_length > 0) { - int64_t pcr = demux_ts_adaptation_field_parse (originalPkt+5, adaptation_field_length); - if (pid == this->pcr_pid) - demux_ts_tbre_update (this, TBRE_MODE_PCR, pcr); - else if (pid == this->tbre_pid) - demux_ts_tbre_update (this, TBRE_MODE_AUDIO_PCR, pcr); - } - /* - * Skip adaptation header. - */ - data_offset += adaptation_field_length + 1; - } - - if (! (adaptation_field_control & 0x1)) { - return; - } - - /* PAT */ - if (pid == 0) { - demux_ts_parse_pat(this, originalPkt, originalPkt+data_offset-4, - payload_unit_start_indicator); - return; - } - - /* PMT */ - program_count=0; - while ((this->program_number[program_count] != INVALID_PROGRAM) && - (program_count < MAX_PMTS)) { - if (pid == this->pmt_pid[program_count]) { - -#ifdef TS_LOG - printf ("demux_ts: PMT prog: 0x%.4x pid: 0x%.4x\n", - this->program_number[program_count], - this->pmt_pid[program_count]); -#endif - demux_ts_parse_pmt (this, originalPkt, originalPkt+data_offset-4, - payload_unit_start_indicator, - program_count); - return; - } - program_count++; - } - - data_len = PKT_SIZE - data_offset; - - if (data_len > PKT_SIZE) { - - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! invalid payload size %d\n", data_len); - - } else { - - /* - * Do the demuxing in descending order of packet frequency! - */ - int index; - if (pid == this->videoPid) { -#ifdef TS_LOG - printf ("demux_ts: Video pid: 0x%.4x\n", pid); -#endif - check_newpts(this, this->media[this->videoMedia].pts, PTS_VIDEO); - demux_ts_buffer_pes (this, originalPkt+data_offset, this->videoMedia, - payload_unit_start_indicator, continuity_counter, - data_len); - return; - } - else if ((index = apid_check(this, pid)) > -1) { -#ifdef TS_LOG - printf ("demux_ts: Audio pid: 0x%.4x\n", pid); -#endif - check_newpts(this, this->media[this->audio_tracks[index].media_index].pts, PTS_AUDIO); - demux_ts_buffer_pes (this, originalPkt+data_offset, - this->audio_tracks[index].media_index, - payload_unit_start_indicator, continuity_counter, - data_len); - return; - } - else if (pid == NULL_PID) { -#ifdef TS_LOG - printf ("demux_ts: Null Packet\n"); -#endif - return; - } - /* DVBSUB */ - else if (pid == this->spu_pid) { -#ifdef TS_LOG - printf ("demux_ts: SPU pid: 0x%.4x\n", pid); -#endif - demux_ts_buffer_pes (this, originalPkt+data_offset, this->spu_media, - payload_unit_start_indicator, continuity_counter, - data_len); - return; - } - } -} - -/* - * check for pids change events - */ - -static void demux_ts_event_handler (demux_ts_t *this) { - - xine_event_t *event; - - while ((event = xine_event_get (this->event_queue))) { - - - switch (event->type) { - - case XINE_EVENT_END_OF_CLIP: - /* flush all streams */ - demux_ts_flush(this); - /* fall thru */ - - case XINE_EVENT_PIDS_CHANGE: - - this->videoPid = INVALID_PID; - this->pcr_pid = INVALID_PID; - this->audio_tracks_count = 0; - this->media_num = 0; - this->send_newpts = 1; - this->spu_pid = INVALID_PID; - this->spu_media = 0; - this->spu_langs_count= 0; - this->last_pmt_crc = 0; - _x_demux_control_start (this->stream); - break; - - } - - xine_event_free (event); - } -} - -/* - * send a piece of data down the fifos - */ - -static int demux_ts_send_chunk (demux_plugin_t *this_gen) { - - demux_ts_t*this = (demux_ts_t*)this_gen; - - demux_ts_event_handler (this); - - demux_ts_parse_packet(this); - - /* DVBSUB: check if channel has changed. Dunno if I should, or - * even could, lock the xine object. */ - if (this->stream->spu_channel != this->current_spu_channel) { - demux_ts_update_spu_channel(this); - } - - return this->status; -} - -static void demux_ts_dispose (demux_plugin_t *this_gen) { - int i; - demux_ts_t*this = (demux_ts_t*)this_gen; - - for (i=0; i < MAX_PMTS; i++) { - if (this->pmt[i] != NULL) { - free(this->pmt[i]); - this->pmt[i] = NULL; - } - } - for (i=0; i < MAX_PIDS; i++) { - if (this->media[i].buf != NULL) { - this->media[i].buf->free_buffer(this->media[i].buf); - this->media[i].buf = NULL; - } - } - - xine_event_dispose_queue (this->event_queue); - - free(this_gen); -} - -static int demux_ts_get_status(demux_plugin_t *this_gen) { - - demux_ts_t*this = (demux_ts_t*)this_gen; - - return this->status; -} - -static void demux_ts_send_headers (demux_plugin_t *this_gen) { - - demux_ts_t *this = (demux_ts_t *) this_gen; - - this->video_fifo = this->stream->video_fifo; - this->audio_fifo = this->stream->audio_fifo; - - this->status = DEMUX_OK; - - /* - * send start buffers - */ - - this->videoPid = INVALID_PID; - this->pcr_pid = INVALID_PID; - this->audio_tracks_count = 0; - this->media_num= 0; - this->last_pmt_crc = 0; - - _x_demux_control_start (this->stream); - - this->input->seek (this->input, 0, SEEK_SET); - - this->send_newpts = 1; - - demux_ts_build_crc32_table (this); - - this->status = DEMUX_OK ; - - this->scrambled_npids = 0; - - /* DVBSUB */ - this->spu_pid = INVALID_PID; - this->spu_langs_count = 0; - this->current_spu_channel = -1; - - /* FIXME ? */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); -} - -static int demux_ts_seek (demux_plugin_t *this_gen, - off_t start_pos, int start_time, int playing) { - - demux_ts_t *this = (demux_ts_t *) this_gen; - int i; - start_pos = (off_t) ( (double) start_pos / 65535 * - this->input->get_length (this->input) ); - - if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { - - if ((!start_pos) && (start_time)) { - - if (this->input->seek_time) { - this->input->seek_time(this->input, start_time, SEEK_SET); - } else { - start_pos = (int64_t)start_time * this->rate / 1000; - this->input->seek (this->input, start_pos, SEEK_SET); - } - - } else { - this->input->seek (this->input, start_pos, SEEK_SET); - } - } - - this->send_newpts = 1; - - for (i=0; i<MAX_PIDS; i++) { - demux_ts_media *m = &this->media[i]; - - if (m->buf != NULL) - m->buf->free_buffer(m->buf); - m->buf = NULL; - m->counter = INVALID_CC; - m->corrupted_pes = 1; - } - - if( !playing ) { - - this->status = DEMUX_OK; - this->buf_flag_seek = 0; - - } else { - - this->buf_flag_seek = 1; - _x_demux_flush_engine(this->stream); - - } - - demux_ts_tbre_reset (this); - - return this->status; -} - -static int demux_ts_get_stream_length (demux_plugin_t *this_gen) { - - demux_ts_t*this = (demux_ts_t*)this_gen; - - if (this->rate) - return (int)((int64_t) this->input->get_length (this->input) - * 1000 / this->rate); - else - return 0; -} - - -static uint32_t demux_ts_get_capabilities(demux_plugin_t *this_gen) -{ - return DEMUX_CAP_AUDIOLANG | DEMUX_CAP_SPULANG; -} - -static void flush_decoders(demux_ts_t *this) -{ - buf_element_t *buf; - xine_stream_t *stream = this->stream; - unsigned int i; - - /* flush demuxer caches*/ - for (i = 0; i < MAX_PIDS; i++) { - demux_ts_flush_media(&this->media[i]); - } - - /* flush decoders */ - buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo); - buf->type = BUF_CONTROL_FLUSH_DECODER; - stream->video_fifo->put (stream->video_fifo, buf); -#if 0 - buf = stream->audio_fifo->buffer_pool_alloc (stream->audio_fifo); - buf->type = BUF_CONTROL_FLUSH_DECODER; - stream->audio_fifo->put (stream->audio_fifo, buf); -#endif - /* reset decoders */ - buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo); - buf->type = BUF_CONTROL_RESET_DECODER; - stream->video_fifo->put (stream->video_fifo, buf); - - buf = stream->audio_fifo->buffer_pool_alloc (stream->audio_fifo); - buf->type = BUF_CONTROL_RESET_DECODER; - stream->audio_fifo->put (stream->audio_fifo, buf); - - /* reset demuxer */ - this->videoPid = INVALID_PID; - this->audio_tracks_count = 0; - this->media_num = 0; - this->send_newpts = 1; - this->spu_pid = INVALID_PID; - this->spu_media = 0; - this->spu_langs_count= 0; - this->last_pmt_crc = 0; - - /* wait until processed */ - _x_demux_control_headers_done (stream); - - /* start */ - _x_demux_control_start (stream); -} - -static int demux_ts_get_optional_data(demux_plugin_t *this_gen, - void *data, int data_type) -{ - demux_ts_t *this = (demux_ts_t *) this_gen; - char *str = data; - - /* be a bit paranoid */ - if (this == NULL || this->stream == NULL || data == NULL) - return DEMUX_OPTIONAL_UNSUPPORTED; - - int channel = *((int *)data); - - switch (data_type) - { - case DEMUX_OPTIONAL_DATA_AUDIOLANG: - if ((channel >= 0) && (channel < this->audio_tracks_count)) { - if(this->audio_tracks[channel].lang[0]) - strcpy(str, this->audio_tracks[channel].lang); - else { - input_plugin_t *input_plugin = this->stream->input_plugin; - /* Language not known. Use track number. */ - sprintf(str, "%3i", channel); - /* Ask input plugin */ - if (input_plugin && input_plugin->get_capabilities (input_plugin) & INPUT_CAP_SPULANG) - return input_plugin->get_optional_data (input_plugin, data, data_type); - } - } - else { - strcpy(str, "none"); - return DEMUX_OPTIONAL_UNSUPPORTED; - } - return DEMUX_OPTIONAL_SUCCESS; - - case DEMUX_OPTIONAL_DATA_SPULANG: - if (channel>=0 && channel<this->spu_langs_count) { - if (this->spu_langs[channel].desc.lang[0]) { - memcpy(str, this->spu_langs[channel].desc.lang, 3); - str[3] = 0; - } else { - input_plugin_t *input_plugin = this->stream->input_plugin; - /* Language not known. Use track number. */ - sprintf(str, "%3i", channel); - /* Ask input plugin */ - if (input_plugin && input_plugin->get_capabilities (input_plugin) & INPUT_CAP_SPULANG) - return input_plugin->get_optional_data (input_plugin, data, data_type); - } - } - else { - strcpy(str, "none"); - return DEMUX_OPTIONAL_UNSUPPORTED; - } - return DEMUX_OPTIONAL_SUCCESS; - - default: - return DEMUX_OPTIONAL_UNSUPPORTED; - } -} - -static int detect_ts(uint8_t *buf, size_t len, unsigned int ts_size) -{ - unsigned int i, try_again; - size_t j, packs; - - if (len < ts_size * 4) { - return 0; - } - - packs = len / ts_size - 2; - - for (i = 0; i < ts_size; i++) { - try_again = 0; - if (buf[i] == SYNC_BYTE) { - for (j = 1; j < packs; j++) { - if (buf[i + j*ts_size] != SYNC_BYTE) { - try_again = 1; - break; - } - } - if (try_again == 0) { -#ifdef TS_LOG - printf ("demux_ts: found 0x47 pattern at offset %d\n", i); -#endif - return 1; - } - } - } - - return 0; -} - -static demux_plugin_t *open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, - input_plugin_t *input) { - - demux_ts_t *this; - int i; - int hdmv = -1; - int size; - - switch (stream->content_detection_method) { - - case METHOD_BY_CONTENT: { - uint8_t buf[2069]; - - size = _x_demux_read_header(input, buf, sizeof(buf)); - if (size < 4 * PKT_SIZE) - return NULL; - - if (detect_ts(buf, size, PKT_SIZE)) - hdmv = 0; - else if (detect_ts(buf, size, PKT_SIZE+4)) - hdmv = 1; - else - return NULL; - } - break; - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 - case METHOD_BY_EXTENSION: -#else - case METHOD_BY_MRL: -#endif - { - const char *const mrl = input->get_mrl (input); - - if (_x_demux_check_extension (mrl, "m2ts mts")) - hdmv = 1; - else - hdmv = 0; - - /* check extension */ -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 - const char *const extensions = class_gen->get_extensions (class_gen); -#else - const char *const extensions = class_gen->extensions; -#endif - if (_x_demux_check_extension (mrl, extensions)) - break; - - /* accept dvb streams */ - /* - * Also handle the special dvbs,dvbt and dvbc mrl formats: - * the content is exactly the same but the input plugin - * uses a different tuning algorithm [Pragma] - */ - - if (!strncasecmp (mrl, "dvb://", 6)) - break; - if (!strncasecmp (mrl, "dvbs://", 7)) - break; - if (!strncasecmp (mrl, "dvbc://", 7)) - break; - if (!strncasecmp (mrl, "dvbt://", 7)) - break; - - /* accept BluRay discs */ - if (!strncasecmp (mrl, "bluray:/", 8) || - !strncasecmp (mrl, "bd:/", 4)) { - hdmv = 1; - break; - } - - return NULL; - } - - case METHOD_EXPLICIT: - break; - - default: - return NULL; - } - - /* - * if we reach this point, the input has been accepted. - */ - - this = calloc(1, sizeof(*this)); - this->stream = stream; - this->input = input; - - this->demux_plugin.send_headers = demux_ts_send_headers; - this->demux_plugin.send_chunk = demux_ts_send_chunk; - this->demux_plugin.seek = demux_ts_seek; - this->demux_plugin.dispose = demux_ts_dispose; - this->demux_plugin.get_status = demux_ts_get_status; - this->demux_plugin.get_stream_length = demux_ts_get_stream_length; - this->demux_plugin.get_capabilities = demux_ts_get_capabilities; - this->demux_plugin.get_optional_data = demux_ts_get_optional_data; - this->demux_plugin.demux_class = class_gen; - - /* - * Initialise our specialised data. - */ - - this->last_pat_crc = 0; - this->transport_stream_id = -1; - - for (i = 0; i < MAX_PIDS; i++) { - this->media[i].pid = INVALID_PID; - this->media[i].buf = NULL; - } - - for (i = 0; i < MAX_PMTS; i++) { - this->program_number[i] = INVALID_PROGRAM; - this->pmt_pid[i] = INVALID_PID; - this->pmt[i] = NULL; - this->pmt_write_ptr[i] = NULL; - } - - this->scrambled_npids = 0; - this->videoPid = INVALID_PID; - this->pcr_pid = INVALID_PID; - this->audio_tracks_count = 0; - this->last_pmt_crc = 0; - - this->rate = xine_get_stream_info(this->stream, XINE_STREAM_INFO_BITRATE); - if (this->rate > 0 && this->rate < 100000000 ) - this->rate /= 8; /* bits/s -> bytes/s */ - else - this->rate = 800000; /* FIXME */ - this->tbre_pid = INVALID_PID; - - this->status = DEMUX_FINISHED; - - /* DVBSUB */ - this->spu_pid = INVALID_PID; - this->spu_langs_count = 0; - this->current_spu_channel = -1; - - /* dvb */ - this->event_queue = xine_event_new_queue (this->stream); - - /* HDMV */ - this->hdmv = hdmv; - this->pkt_offset = (hdmv > 0) ? 4 : 0; - this->pkt_size = PKT_SIZE + this->pkt_offset; - - return &this->demux_plugin; -} - -/* - * ts demuxer class - */ - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *get_description (demux_class_t *this_gen) { - return "MPEG Transport Stream demuxer (HDMV)"; -} -#endif - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *get_identifier (demux_class_t *this_gen) { - return "MPEG_TS_HDMV"; -} -#endif - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *get_extensions (demux_class_t *this_gen) { - return "m2ts mts"; -} -#endif - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; -} -#endif - -static void class_dispose (demux_class_t *this_gen) { - - demux_ts_class_t *this = (demux_ts_class_t *) this_gen; - - free (this); -} - -static void *init_class (xine_t *xine, void *data) { - - demux_ts_class_t *this; - - this = calloc(1, sizeof(demux_ts_class_t)); - this->config = xine->config; - this->xine = xine; - - this->demux_class.open_plugin = open_plugin; -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 - 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; -#else - this->demux_class.description = "MPEG Transport Stream demuxer (HDMV)"; - this->demux_class.identifier = "MPEG_TS_HDMV"; - this->demux_class.mimetypes = NULL; - this->demux_class.extensions = "m2ts mts"; -#endif - this->demux_class.dispose = class_dispose; - - return this; -} - - -/* - * exported plugin catalog entry - */ -static const demuxer_info_t demux_info_ts = { - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ -#if DEMUX_PLUGIN_IFACE_VERSION <= 26 - { PLUGIN_DEMUX, 26, "mpeg-ts-hdmv", XINE_VERSION_CODE, &demux_info_ts, init_class }, -#elif DEMUX_PLUGIN_IFACE_VERSION >= 27 - { PLUGIN_DEMUX, 27, "mpeg-ts-hdmv", XINE_VERSION_CODE, &demux_info_ts, init_class }, -#endif - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - diff --git a/xine/BluRay/input_bluray.c b/xine/BluRay/input_bluray.c deleted file mode 100644 index 6261eafb..00000000 --- a/xine/BluRay/input_bluray.c +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * Copyright (C) 2000-2011 the xine project - * Copyright (C) 2009-2011 Petri Hintukainen <phintuka@users.sourceforge.net> - * - * 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 - * - * Input plugin for BluRay discs / images - * - * Requires libbluray 0.2.1 or later: - * http://www.videolan.org/developers/libbluray.html - * git://git.videolan.org/libbluray.git - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* asprintf: */ -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <pthread.h> - -/* for loop device (used with .iso images) */ -#include <sys/mount.h> -#include <linux/fs.h> -#include <linux/loop.h> -#include <fcntl.h> -#include <sys/ioctl.h> - -/* libbluray */ -#include <libbluray/bluray.h> -#include <libbluray/bluray-version.h> -#include <libbluray/keys.h> -#include <libbluray/overlay.h> -#include <libbluray/meta_data.h> - -/* xine */ - -#define LOG_MODULE "input_bluray" -#define LOG_VERBOSE - -#define LOG - -#define LOGMSG(x...) xine_log (this->stream->xine, XINE_LOG_MSG, "input_bluray: " x); - -#define XINE_ENGINE_INTERNAL - -#ifdef HAVE_CONFIG_H -# include "xine_internal.h" -# include "input_plugin.h" -#else -# include <xine/xine_internal.h> -# include <xine/input_plugin.h> -#endif - -#ifndef XINE_VERSION_CODE -# error XINE_VERSION_CODE undefined ! -#endif - -#ifndef EXPORTED -# define EXPORTED __attribute__((visibility("default"))) -#endif - -#ifndef XINE_EVENT_END_OF_CLIP -# define XINE_EVENT_END_OF_CLIP 0x80000001 -#endif - -/* */ - -#ifndef MIN -# define MIN(a,b) ((a)<(b)?(a):(b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a)>(b)?(a):(b)) -#endif - -#define ALIGNED_UNIT_SIZE 6144 -#define PKT_SIZE 192 -#define TICKS_IN_MS 45 - -#define MIN_TITLE_LENGTH 180 - -/* */ - -typedef struct { - - input_class_t input_class; - - xine_t *xine; - - xine_mrl_t **xine_playlist; - int xine_playlist_size; - - /* config */ - char *mountpoint; - char *device; - char *language; - char *country; - int region; - int parental; -} bluray_input_class_t; - -typedef struct { - input_plugin_t input_plugin; - - bluray_input_class_t *class; - - xine_stream_t *stream; - xine_event_queue_t *event_queue; - xine_osd_t *osd[2]; - - char *mrl; - char *disc_root; - char *disc_name; - - BLURAY *bdh; - - const BLURAY_DISC_INFO *disc_info; - const META_DL *meta_dl; /* disc library meta data */ - - int num_title_idx; /* number of relevant playlists */ - int current_title_idx; - int num_titles; /* navigation mode, number of titles in disc index */ - int current_title; /* navigation mode, title from disc index */ - BLURAY_TITLE_INFO *title_info; - pthread_mutex_t title_info_mutex; /* lock this when accessing title_info outside of input/demux thread */ - unsigned int current_clip; - time_t still_end_time; - int pg_stream; - - uint8_t nav_mode : 1; - uint8_t error : 1; - uint8_t menu_open : 1; - uint8_t stream_flushed : 1; - uint8_t demux_action_req : 1; - uint8_t end_of_title : 1; - uint8_t pg_enable : 1; - int mouse_inside_button; - - uint32_t cap_seekable; - - /* loop device for .iso image */ - char *iso_image; - char *loop_dev; - char mount_point[64]; - -} bluray_input_plugin_t; - -/* - * Loop device setup stuff, swiped from busybox. - */ - -int del_loop(const char *device) -{ - int fd; - - if ((fd = open(device, O_RDONLY)) < 0) { - perror(device); - return -1; - } - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - close(fd); -/* umm... why? perror("ioctl: LOOP_CLR_FD"); */ - return -1; - } - close(fd); - return 0; -} - -int set_loop(const char *device, const char *file, int offset, int *loopro) -{ - struct loop_info loopinfo; - int fd, ffd, mode; - - mode = *loopro ? O_RDONLY : O_RDWR; - if ((ffd = open (file, mode)) < 0 && !*loopro - && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { - perror (file); - return 1; - } - if ((fd = open (device, mode)) < 0) { - close(ffd); - perror(device); - return 1; - } - *loopro = (mode == O_RDONLY); - - memset(&loopinfo, 0, sizeof(loopinfo)); - strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); - loopinfo.lo_name[LO_NAME_SIZE-1] = 0; - - loopinfo.lo_offset = offset; - - loopinfo.lo_encrypt_key_size = 0; - if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { - perror("ioctl: LOOP_SET_FD"); - close(fd); - close(ffd); - return 1; - } - if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { - (void) ioctl(fd, LOOP_CLR_FD, 0); - perror("ioctl: LOOP_SET_STATUS"); - close(fd); - close(ffd); - return 1; - } - close(fd); - close(ffd); - return 0; -} - -char *find_unused_loop_device (void) -{ - char dev[20]; - int i, fd; - struct stat statbuf; - struct loop_info loopinfo; - - for(i = 0; i <= 7; i++) { - sprintf(dev, "/dev/loop%d", i); - if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { - if ((fd = open (dev, O_RDONLY)) >= 0) { - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1) { - if (errno == ENXIO) { /* probably free */ - close (fd); - return strdup(dev); - } - } - close (fd); - } - } - } - return NULL; -} - -/* - * - */ - -static void close_loop_device (bluray_input_plugin_t *this) -{ - if (this->iso_image) { - umount(this->mount_point); - rmdir(this->mount_point); - free(this->iso_image); - this->iso_image = NULL; - } - if (this->loop_dev) { - del_loop(this->loop_dev); - free(this->loop_dev); - this->loop_dev = NULL; - } -} - -static int mount_iso_image(bluray_input_plugin_t *this) -{ - close_loop_device(this); - - /* create temporary mount point */ - sprintf(this->mount_point, "/tmp/xine_bd.%d.XXXXXX", (int)getpid()); - if (mktemp(this->mount_point)) {}; - if (mkdir(this->mount_point, S_IRWXU)) { - LOGMSG("Failed to create temporary mount point %s: %s\n", - this->mount_point, strerror(errno)); - return 0; - } - - /* find and initialize unused loop device */ - - this->loop_dev = find_unused_loop_device(); - if (!this->loop_dev) { - LOGMSG("No free loop device for %s\n", this->disc_root); - return 0; - } - - int pro = O_RDONLY; - if (set_loop(this->loop_dev, this->disc_root, 0, &pro)) { - LOGMSG("Error setting up loop device %s for %s\n", this->loop_dev, this->disc_root); - return 0; - } - - /* mount .iso image */ - if (mount(this->loop_dev, this->mount_point, "udf", - MS_NODEV | MS_MGC_VAL | MS_NOSUID | MS_RDONLY, NULL)) { - LOGMSG("Error mounting loop device %s to %s\n", this->loop_dev, this->mount_point); - return 0; - } - - this->iso_image = this->disc_root; - this->disc_root = strdup(this->mount_point); - - LOGMSG("Mounted %s to %s using loop device %s\n", this->iso_image, this->mount_point, this->loop_dev); - - return 1; -} - -/* - * overlay - */ - -#define PALETTE_INDEX_BACKGROUND 0xff - -static void send_num_buttons(bluray_input_plugin_t *this, int n) -{ - xine_event_t event; - xine_ui_data_t data; - - event.type = XINE_EVENT_UI_NUM_BUTTONS; - event.data = &data; - event.data_length = sizeof(data); - data.num_buttons = n; - - xine_event_send(this->stream, &event); -} - -static void clear_overlay(xine_osd_t *osd) -{ - /* palette entry 0xff is background --> can't use xine_osd_clear(). */ - memset(osd->osd.area, PALETTE_INDEX_BACKGROUND, osd->osd.width * osd->osd.height); - osd->osd.x1 = osd->osd.width; - osd->osd.y1 = osd->osd.height; - osd->osd.x2 = 0; - osd->osd.y2 = 0; -} - -static xine_osd_t *get_overlay(bluray_input_plugin_t *this, int plane) -{ - if (!this->osd[plane]) { - this->osd[plane] = xine_osd_new(this->stream, 0, 0, 1920, 1080); - clear_overlay(this->osd[plane]); - } - if (!this->pg_enable) { - _x_select_spu_channel(this->stream, -1); - } - return this->osd[plane]; -} - -static void close_overlay(bluray_input_plugin_t *this, int plane) -{ - if (plane < 0) { - close_overlay(this, 0); - close_overlay(this, 1); - return; - } - - if (plane < 2 && this->osd[plane]) { - xine_osd_free(this->osd[plane]); - this->osd[plane] = NULL; - if (plane == 1) { - send_num_buttons(this, 0); - this->menu_open = 0; - } - } -} - -static void open_overlay(bluray_input_plugin_t *this, const BD_OVERLAY * const ov) -{ - lprintf("open_overlay(%d,%d)\n", ov->w, ov->h); - - if (this->osd[ov->plane]) { - close_overlay(this, ov->plane); - } - - this->osd[ov->plane] = xine_osd_new(this->stream, ov->x, ov->y, ov->w, ov->h); - clear_overlay(this->osd[ov->plane]); -} - -static void draw_bitmap(xine_osd_t *osd, const BD_OVERLAY * const ov) -{ - unsigned i; - - /* convert and set palette */ - if (ov->palette) { - uint32_t color[256]; - uint8_t trans[256]; - for(i = 0; i < 256; i++) { - trans[i] = ov->palette[i].T; - color[i] = (ov->palette[i].Y << 16) | (ov->palette[i].Cr << 8) | ov->palette[i].Cb; - } - - xine_osd_set_palette(osd, color, trans); - } - - /* uncompress and draw bitmap */ - if (ov->img) { - const BD_PG_RLE_ELEM *rlep = ov->img; - uint8_t *img = malloc(ov->w * ov->h); - unsigned pixels = ov->w * ov->h; - - for (i = 0; i < pixels; i += rlep->len, rlep++) { - memset(img + i, rlep->color, rlep->len); - } - - xine_osd_draw_bitmap(osd, img, ov->x, ov->y, ov->w, ov->h, NULL); - - free(img); - } -} - -static void overlay_proc(void *this_gen, const BD_OVERLAY * const ov) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - xine_osd_t *osd; - - if (!this) { - return; - } - - if (!ov) { - /* hide OSD */ - close_overlay(this, -1); - return; - } - - if (ov->plane > 1) { - return; - } - - switch (ov->cmd) { - case BD_OVERLAY_INIT: /* init overlay plane. Size of full plane in x,y,w,h */ - open_overlay(this, ov); - return; - case BD_OVERLAY_CLOSE: /* close overlay */ - close_overlay(this, ov->plane); - return; - } - - osd = get_overlay(this, ov->plane); - - switch (ov->cmd) { - case BD_OVERLAY_DRAW: /* draw bitmap (x,y,w,h,img,palette) */ - draw_bitmap(osd, ov); - return; - - case BD_OVERLAY_WIPE: /* clear area (x,y,w,h) */ - xine_osd_draw_rect(osd, ov->x, ov->y, ov->x + ov->w - 1, ov->y + ov->h - 1, PALETTE_INDEX_BACKGROUND, 1); - return; - - case BD_OVERLAY_CLEAR: /* clear plane */ - xine_osd_hide(osd, 0); - clear_overlay(osd); - return; - - case BD_OVERLAY_FLUSH: /* all changes have been done, flush overlay to display at given pts */ - xine_osd_show(osd, 0); - - if (ov->plane == 1) { - this->menu_open = 1; - send_num_buttons(this, 1); - } - return; - - default: - LOGMSG("unknown overlay command %d\n", ov->cmd); - return; - } -} - -/* - * stream info - */ - -static void update_stream_info(bluray_input_plugin_t *this) -{ - if (this->title_info) { - /* set stream info */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_COUNT, this->title_info->angle_count); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_CHAPTERS, this->title_info->chapter_count > 0); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT, this->title_info->chapter_count); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, bd_get_current_chapter(this->bdh) + 1); - } -} - -static void update_title_name(bluray_input_plugin_t *this) -{ - char title_name[64] = ""; - xine_ui_data_t udata; - xine_event_t uevent = { - .type = XINE_EVENT_UI_SET_TITLE, - .stream = this->stream, - .data = &udata, - .data_length = sizeof(udata) - }; - - /* check disc library metadata */ - if (this->meta_dl) { - unsigned i; - for (i = 0; i < this->meta_dl->toc_count; i++) - if (this->meta_dl->toc_entries[i].title_number == (unsigned)this->current_title) - if (this->meta_dl->toc_entries[i].title_name) - if (strlen(this->meta_dl->toc_entries[i].title_name) > 2) - strncpy(title_name, this->meta_dl->toc_entries[i].title_name, sizeof(title_name)); - } - - /* title name */ - if (title_name[0]) { - } else if (this->current_title == BLURAY_TITLE_TOP_MENU) { - strcpy(title_name, "Top Menu"); - } else if (this->current_title == BLURAY_TITLE_FIRST_PLAY) { - strcpy(title_name, "First Play"); - } else if (this->nav_mode) { - snprintf(title_name, sizeof(title_name), "Title %d/%d (PL %d/%d)", - this->current_title, this->num_titles, - this->current_title_idx + 1, this->num_title_idx); - } else { - snprintf(title_name, sizeof(title_name), "Title %d/%d", - this->current_title_idx + 1, this->num_title_idx); - } - - /* disc name */ - if (this->disc_name && this->disc_name[0]) { - udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s, %s", - this->disc_name, title_name); - } else { - udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s", - title_name); - } - - _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, udata.str); - - xine_event_send(this->stream, &uevent); -} - -static void update_title_info(bluray_input_plugin_t *this, int playlist_id) -{ - /* update title_info */ - - pthread_mutex_lock(&this->title_info_mutex); - - if (this->title_info) - bd_free_title_info(this->title_info); - - if (playlist_id < 0) - this->title_info = bd_get_title_info(this->bdh, this->current_title_idx, 0); - else - this->title_info = bd_get_playlist_info(this->bdh, playlist_id, 0); - - pthread_mutex_unlock(&this->title_info_mutex); - - if (!this->title_info) { - LOGMSG("bd_get_title_info(%d) failed\n", this->current_title_idx); - return; - } - -#ifdef LOG - int ms = this->title_info->duration / INT64_C(90); - lprintf("Opened title %d. Length %"PRId64" bytes / %02d:%02d:%02d.%03d\n", - this->current_title_idx, bd_get_title_size(this->bdh), - ms / 3600000, (ms % 3600000 / 60000), (ms % 60000) / 1000, ms % 1000); -#endif - - /* calculate and set stream rate */ - - uint64_t rate = bd_get_title_size(this->bdh) * UINT64_C(8) // bits - * INT64_C(90000) - / (uint64_t)(this->title_info->duration); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, rate); - -#ifdef LOG - int krate = (int)(rate / UINT64_C(1024)); - int s = this->title_info->duration / 90000; - int h = s / 3600; s -= h*3600; - int m = s / 60; s -= m*60; - int f = this->title_info->duration % 90000; f = f * 1000 / 90000; - LOGMSG("BluRay stream: length: %d:%d:%d.%03d\n" - " bitrate: %d.%03d Mbps\n\n", - h, m, s, f, krate/1024, (krate%1024)*1000/1024); -#endif - - /* set stream info */ - - if (this->nav_mode) { - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_titles); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title); - } else { - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_title_idx); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title_idx + 1); - } - - update_stream_info(this); - - /* set title */ - update_title_name(this); -} - -/* - * libbluray event handling - */ - -static void stream_flush(bluray_input_plugin_t *this) -{ - if (this->stream_flushed || !this->stream) - return; - - lprintf("Stream flush\n"); - - this->stream_flushed = 1; - - xine_event_t event = { - .type = XINE_EVENT_END_OF_CLIP, - .stream = this->stream, - .data = NULL, - .data_length = 0, - }; - xine_event_send (this->stream, &event); - - this->demux_action_req = 1; -} - -static void stream_reset(bluray_input_plugin_t *this) -{ - if (!this || !this->stream || !this->stream->demux_plugin) - return; - - lprintf("Stream reset\n"); - -#if XINE_VERSION_CODE < 10121 - this->cap_seekable = 0; - - _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL); - this->stream->demux_plugin->seek(this->stream->demux_plugin, 0, 0, 1); - _x_demux_control_start(this->stream); - - this->cap_seekable = INPUT_CAP_SEEKABLE; -#else - xine_event_t event = { - .type = XINE_EVENT_PIDS_CHANGE, - .stream = this->stream, - .data = NULL, - .data_length = 0, - }; - - if (!this->end_of_title) { - _x_demux_flush_engine(this->stream); - } - - xine_event_send (this->stream, &event); - - this->demux_action_req = 1; -#endif -} - -static void wait_secs(bluray_input_plugin_t *this, unsigned seconds) -{ - stream_flush(this); - - if (this->still_end_time) { - if (time(NULL) >= this->still_end_time) { - lprintf("pause end\n"); - this->still_end_time = 0; - bd_read_skip_still(this->bdh); - stream_reset(this); - return; - } - } - - else if (seconds) { - if (seconds > 300) { - seconds = 300; - } - - lprintf("still image, pause for %d seconds\n", seconds); - this->still_end_time = time(NULL) + seconds; - } - - xine_usec_sleep(40*1000); -} - -static void update_spu_channel(bluray_input_plugin_t *this, int channel) -{ - if (this->stream->video_fifo) { - buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo); - buf->type = BUF_CONTROL_SPU_CHANNEL; - buf->decoder_info[0] = channel; - buf->decoder_info[1] = channel; - buf->decoder_info[2] = channel; - - this->stream->video_fifo->put(this->stream->video_fifo, buf); - } -} - -static void update_audio_channel(bluray_input_plugin_t *this, int channel) -{ - if (this->stream->audio_fifo) { - buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo); - buf->type = BUF_CONTROL_AUDIO_CHANNEL; - buf->decoder_info[0] = channel; - - this->stream->audio_fifo->put(this->stream->audio_fifo, buf); - } -} - -static void handle_libbluray_event(bluray_input_plugin_t *this, BD_EVENT ev) -{ - switch ((bd_event_e)ev.event) { - - case BD_EVENT_NONE: - break; - - case BD_EVENT_ERROR: - LOGMSG("BD_EVENT_ERROR\n"); - this->error = 1; - return; - - case BD_EVENT_READ_ERROR: - LOGMSG("BD_EVENT_READ_ERROR\n"); - return; - - case BD_EVENT_ENCRYPTED: - lprintf("BD_EVENT_ENCRYPTED\n"); - _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, - "Media stream scrambled/encrypted", NULL); - this->error = 1; - return; - - /* sound effects */ -#if BLURAY_VERSION >= 202 - case BD_EVENT_SOUND_EFFECT: - lprintf("BD_EVENT_SOUND_EFFECT %d\n", ev.param); - break; -#endif - - /* playback control */ - - case BD_EVENT_SEEK: - lprintf("BD_EVENT_SEEK\n"); - this->still_end_time = 0; - stream_reset(this); - break; - - case BD_EVENT_STILL_TIME: - wait_secs(this, ev.param); - break; - - case BD_EVENT_STILL: - lprintf("BD_EVENT_STILL %d\n", ev.param); - int paused = _x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE; - if (paused && !ev.param) { - _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL); - } - if (!paused && ev.param) { - _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE); - } - break; - - /* playback position */ - - case BD_EVENT_ANGLE: - lprintf("BD_EVENT_ANGLE_NUMBER %d\n", ev.param); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, ev.param); - break; - - case BD_EVENT_END_OF_TITLE: - lprintf("BD_EVENT_END_OF_TITLE\n"); - stream_flush(this); - this->end_of_title = 1; - break; - - case BD_EVENT_TITLE: - if (this->nav_mode) { - lprintf("BD_EVENT_TITLE %d\n", ev.param); - this->current_title = ev.param; - } - break; - - case BD_EVENT_PLAYLIST: - lprintf("BD_EVENT_PLAYLIST %d\n", ev.param); - this->current_title_idx = bd_get_current_title(this->bdh); - this->current_clip = 0; - update_title_info(this, ev.param); - stream_reset(this); - this->end_of_title = 0; - break; - - case BD_EVENT_PLAYITEM: - lprintf("BD_EVENT_PLAYITEM %d\n", ev.param); - this->current_clip = ev.param; - this->still_end_time = 0; - break; - - case BD_EVENT_CHAPTER: - lprintf("BD_EVENT_CHAPTER %d\n", ev.param); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, ev.param); - break; - - /* stream selection */ - - case BD_EVENT_AUDIO_STREAM: - lprintf("BD_EVENT_AUDIO_STREAM %d\n", ev.param); - if (ev.param < 32) { - update_audio_channel(this, ev.param - 1); - } else { - update_audio_channel(this, 0); - } - break; - - case BD_EVENT_PG_TEXTST: - lprintf("BD_EVENT_PG_TEXTST %s\n", ev.param ? "ON" : "OFF"); - this->pg_enable = !!ev.param; - update_spu_channel(this, this->pg_enable ? this->pg_stream : -1); - break; - - case BD_EVENT_PG_TEXTST_STREAM: - lprintf("BD_EVENT_PG_TEXTST_STREAM %d\n", ev.param); - if (ev.param < 64) { - this->pg_stream = ev.param - 1; - } else { - this->pg_stream = -1; - } - if (this->pg_enable) { - update_spu_channel(this, this->pg_stream); - } - break; - - case BD_EVENT_IG_STREAM: - case BD_EVENT_SECONDARY_AUDIO: - case BD_EVENT_SECONDARY_AUDIO_STREAM: - case BD_EVENT_SECONDARY_VIDEO: - case BD_EVENT_SECONDARY_VIDEO_SIZE: - case BD_EVENT_SECONDARY_VIDEO_STREAM: - // TODO - - default: - lprintf("unhandled libbluray event %d [param %d]\n", ev.event, ev.param); - break; - } -} - -static void handle_libbluray_events(bluray_input_plugin_t *this) -{ - BD_EVENT ev; - while (bd_get_event(this->bdh, &ev)) { - handle_libbluray_event(this, ev); - if (this->error || ev.event == BD_EVENT_NONE || ev.event == BD_EVENT_ERROR) - break; - } -} - -/* - * xine event handling - */ - -static int open_title (bluray_input_plugin_t *this, int title_idx) -{ - if (bd_select_title(this->bdh, title_idx) <= 0) { - LOGMSG("bd_select_title(%d) failed\n", title_idx); - return 0; - } - - this->current_title_idx = title_idx; - - update_title_info(this, -1); - - return 1; -} - -static void send_mouse_enter_leave_event(bluray_input_plugin_t *this, int direction) -{ - if (direction != this->mouse_inside_button) { - xine_event_t event; - xine_spu_button_t spu_event; - - spu_event.direction = direction; - spu_event.button = 1; - - event.type = XINE_EVENT_SPU_BUTTON; - event.stream = this->stream; - event.data = &spu_event; - event.data_length = sizeof(spu_event); - xine_event_send(this->stream, &event); - - this->mouse_inside_button = direction; - } -} - -static void handle_events(bluray_input_plugin_t *this) -{ - if (!this->event_queue) - return; - - xine_event_t *event; - while (NULL != (event = xine_event_get(this->event_queue))) { - - if (!this->bdh || !this->title_info) { - xine_event_free(event); - return; - } - - int64_t pts = xine_get_current_vpts(this->stream) - - this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); - - if (this->menu_open) { - switch (event->type) { - case XINE_EVENT_INPUT_LEFT: bd_user_input(this->bdh, pts, BD_VK_LEFT); break; - case XINE_EVENT_INPUT_RIGHT: bd_user_input(this->bdh, pts, BD_VK_RIGHT); break; - } - } else { - switch (event->type) { - - case XINE_EVENT_INPUT_LEFT: - lprintf("XINE_EVENT_INPUT_LEFT: previous title\n"); - if (!this->nav_mode) { - open_title(this, MAX(0, this->current_title_idx - 1)); - } else { - bd_play_title(this->bdh, MAX(1, this->current_title - 1)); - } - stream_reset(this); - break; - - case XINE_EVENT_INPUT_RIGHT: - lprintf("XINE_EVENT_INPUT_RIGHT: next title\n"); - if (!this->nav_mode) { - open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1)); - } else { - bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1)); - } - stream_reset(this); - break; - } - } - - switch (event->type) { - - case XINE_EVENT_INPUT_MOUSE_BUTTON: { - xine_input_data_t *input = event->data; - lprintf("mouse click: button %d at (%d,%d)\n", input->button, input->x, input->y); - if (input->button == 1) { - bd_mouse_select(this->bdh, pts, input->x, input->y); - bd_user_input(this->bdh, pts, BD_VK_MOUSE_ACTIVATE); - send_mouse_enter_leave_event(this, 0); - } - break; - } - - case XINE_EVENT_INPUT_MOUSE_MOVE: { - xine_input_data_t *input = event->data; - if (bd_mouse_select(this->bdh, pts, input->x, input->y) > 0) { - send_mouse_enter_leave_event(this, 1); - } else { - send_mouse_enter_leave_event(this, 0); - } - break; - } - - case XINE_EVENT_INPUT_MENU1: - if (!this->disc_info->top_menu_supported) { - _x_message (this->stream, XINE_MSG_GENERAL_WARNING, - "Can't open Top Menu", - "Top Menu title not supported", NULL); - } - bd_menu_call(this->bdh, pts); - break; - - case XINE_EVENT_INPUT_MENU2: bd_user_input(this->bdh, pts, BD_VK_POPUP); break; - case XINE_EVENT_INPUT_UP: bd_user_input(this->bdh, pts, BD_VK_UP); break; - case XINE_EVENT_INPUT_DOWN: bd_user_input(this->bdh, pts, BD_VK_DOWN); break; - case XINE_EVENT_INPUT_SELECT: bd_user_input(this->bdh, pts, BD_VK_ENTER); break; - case XINE_EVENT_INPUT_NUMBER_0: bd_user_input(this->bdh, pts, BD_VK_0); break; - case XINE_EVENT_INPUT_NUMBER_1: bd_user_input(this->bdh, pts, BD_VK_1); break; - case XINE_EVENT_INPUT_NUMBER_2: bd_user_input(this->bdh, pts, BD_VK_2); break; - case XINE_EVENT_INPUT_NUMBER_3: bd_user_input(this->bdh, pts, BD_VK_3); break; - case XINE_EVENT_INPUT_NUMBER_4: bd_user_input(this->bdh, pts, BD_VK_4); break; - case XINE_EVENT_INPUT_NUMBER_5: bd_user_input(this->bdh, pts, BD_VK_5); break; - case XINE_EVENT_INPUT_NUMBER_6: bd_user_input(this->bdh, pts, BD_VK_6); break; - case XINE_EVENT_INPUT_NUMBER_7: bd_user_input(this->bdh, pts, BD_VK_7); break; - case XINE_EVENT_INPUT_NUMBER_8: bd_user_input(this->bdh, pts, BD_VK_8); break; - case XINE_EVENT_INPUT_NUMBER_9: bd_user_input(this->bdh, pts, BD_VK_9); break; - - case XINE_EVENT_INPUT_NEXT: { - cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config, - "media.bluray.skip_behaviour"); - switch (entry->num_value) { - case 0: /* skip by chapter */ - bd_seek_chapter(this->bdh, bd_get_current_chapter(this->bdh) + 1); - update_stream_info(this); - break; - case 1: /* skip by title */ - if (!this->nav_mode) { - open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1)); - } else { - bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1)); - } - break; - } - stream_reset(this); - break; - } - - case XINE_EVENT_INPUT_PREVIOUS: { - cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config, - "media.bluray.skip_behaviour"); - switch (entry->num_value) { - case 0: /* skip by chapter */ - bd_seek_chapter(this->bdh, MAX(0, ((int)bd_get_current_chapter(this->bdh)) - 1)); - update_stream_info(this); - break; - case 1: /* skip by title */ - if (!this->nav_mode) { - open_title(this, MAX(0, this->current_title_idx - 1)); - } else { - bd_play_title(this->bdh, MAX(1, this->current_title - 1)); - } - break; - } - stream_reset(this); - break; - } - - case XINE_EVENT_INPUT_ANGLE_NEXT: { - unsigned curr_angle = bd_get_current_angle(this->bdh); - unsigned angle = MIN(8, curr_angle + 1); - lprintf("XINE_EVENT_INPUT_ANGLE_NEXT: set angle %d --> %d\n", curr_angle, angle); - bd_seamless_angle_change(this->bdh, angle); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); - break; - } - - case XINE_EVENT_INPUT_ANGLE_PREVIOUS: { - unsigned curr_angle = bd_get_current_angle(this->bdh); - unsigned angle = curr_angle ? curr_angle - 1 : 0; - lprintf("XINE_EVENT_INPUT_ANGLE_PREVIOUS: set angle %d --> %d\n", curr_angle, angle); - bd_seamless_angle_change(this->bdh, angle); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); - break; - } - } - - xine_event_free(event); - } -} - -/* - * xine plugin interface - */ - -static uint32_t bluray_plugin_get_capabilities (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - return this->cap_seekable | - INPUT_CAP_BLOCK | - INPUT_CAP_AUDIOLANG | - INPUT_CAP_SPULANG | - INPUT_CAP_CHAPTERS; -} - -#if XINE_VERSION_CODE >= 10121 -# define CHECK_READ_INTERRUPT \ - do { \ - if (this->demux_action_req) { \ - this->demux_action_req = 0; \ - errno = EAGAIN; \ - return -1; \ - } \ - } while (0) -#else -# define CHECK_READ_INTERRUPT -#endif - - -#if XINE_VERSION_CODE >= 10190 -static off_t bluray_plugin_read (input_plugin_t *this_gen, void *buf, off_t len) -#else -static off_t bluray_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) -#endif -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - off_t result; - - if (!this || !this->bdh || len < 0 || this->error) - return -1; - - handle_events(this); - CHECK_READ_INTERRUPT; - - if (this->nav_mode) { - do { - BD_EVENT ev; - result = bd_read_ext (this->bdh, (unsigned char *)buf, len, &ev); - handle_libbluray_event(this, ev); - CHECK_READ_INTERRUPT; - - if (result == 0) { - handle_events(this); - CHECK_READ_INTERRUPT; - - if (ev.event == BD_EVENT_NONE) { - if (_x_action_pending(this->stream)) { - break; - } - } - } - } while (!this->error && result == 0); - } else { - result = bd_read (this->bdh, (unsigned char *)buf, len); - handle_libbluray_events(this); - } - - if (result < 0) - LOGMSG("bd_read() failed: %s (%d of %d)\n", strerror(errno), (int)result, (int)len); - - if (result > 0) - this->stream_flushed = 0; - - return result; -} - -static buf_element_t *bluray_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) -{ - buf_element_t *buf = fifo->buffer_pool_alloc (fifo); - - if (todo > (off_t)buf->max_size) - todo = buf->max_size; - - if (todo > ALIGNED_UNIT_SIZE) - todo = ALIGNED_UNIT_SIZE; - - if (todo > 0) { - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - buf->size = bluray_plugin_read(this_gen, (char*)buf->mem, todo); - buf->type = BUF_DEMUX_BLOCK; - - if (buf->size > 0) { - buf->extra_info->input_time = 0; - buf->extra_info->total_time = this->title_info->duration / 90000; - return buf; - } - } - - buf->free_buffer (buf); - return NULL; -} - -static off_t bluray_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - if (!this || !this->bdh) - return -1; - if (this->still_end_time) - return offset; - - /* convert relative seeks to absolute */ - - if (origin == SEEK_CUR) { - offset = bd_tell(this->bdh) + offset; - } - else if (origin == SEEK_END) { - if (offset < (off_t)bd_get_title_size(this->bdh)) - offset = bd_get_title_size(this->bdh) - offset; - else - offset = 0; - } - - lprintf("bluray_plugin_seek() seeking to %lld\n", (long long)offset); - - return bd_seek (this->bdh, offset); -} - -static off_t bluray_plugin_seek_time (input_plugin_t *this_gen, int time_offset, int origin) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - if (!this || !this->bdh) - return -1; - - if (this->still_end_time) - return bd_tell(this->bdh); - - /* convert relative seeks to absolute */ - - if (origin == SEEK_CUR) { - time_offset += this_gen->get_current_time(this_gen); - } - else if (origin == SEEK_END) { - - pthread_mutex_lock(&this->title_info_mutex); - - if (!this->title_info) { - pthread_mutex_unlock(&this->title_info_mutex); - return -1; - } - - int duration = this->title_info->duration / 90; - if (time_offset < duration) - time_offset = duration - time_offset; - else - time_offset = 0; - - pthread_mutex_unlock(&this->title_info_mutex); - } - - lprintf("bluray_plugin_seek_time() seeking to %d.%03ds\n", time_offset / 1000, time_offset % 1000); - - return bd_seek_time(this->bdh, time_offset * INT64_C(90)); -} - -static off_t bluray_plugin_get_current_pos (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - return this->bdh ? bd_tell(this->bdh) : 0; -} - -static int bluray_plugin_get_current_time (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - return this->bdh ? (int)(bd_tell_time(this->bdh) / UINT64_C(90)) : -1; -} - -static off_t bluray_plugin_get_length (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - return this->bdh ? (off_t)bd_get_title_size(this->bdh) : (off_t)-1; -} - -static uint32_t bluray_plugin_get_blocksize (input_plugin_t *this_gen) -{ - (void)this_gen; - - return ALIGNED_UNIT_SIZE; -} - -static const char* bluray_plugin_get_mrl (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - return this->mrl; -} - -static int get_audio_lang (bluray_input_plugin_t *this, int *data) -{ - /* - * audio track language: - * - channel number can be mpeg-ts PID (0x1100 ... 0x11ff) - */ - - unsigned int current_clip = this->current_clip; /* can change any time */ - - if (this->title_info && current_clip < this->title_info->clip_count) { - int channel = *data; - BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip]; - - if (channel >= 0 && channel < clip->audio_stream_count) { - memcpy(data, clip->audio_streams[channel].lang, 4); - return INPUT_OPTIONAL_SUCCESS; - } - - /* search by pid */ - int i; - for (i = 0; i < clip->audio_stream_count; i++) { - if (channel == clip->audio_streams[i].pid) { - memcpy(data, clip->audio_streams[i].lang, 4); - return INPUT_OPTIONAL_SUCCESS; - } - } - } - - return INPUT_OPTIONAL_UNSUPPORTED; -} - -static int get_spu_lang (bluray_input_plugin_t *this, int *data) -{ - /* - * SPU track language: - * - channel number can be mpeg-ts PID (0x1200 ... 0x12ff) - */ - - unsigned int current_clip = this->current_clip; /* can change any time */ - - if (this->title_info && current_clip < this->title_info->clip_count) { - int channel = *data; - BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip]; - - if (channel >= 0 && channel < clip->pg_stream_count) { - memcpy(data, clip->pg_streams[channel].lang, 4); - return INPUT_OPTIONAL_SUCCESS; - } - - /* search by pid */ - int i; - for (i = 0; i < clip->pg_stream_count; i++) { - if (channel == clip->pg_streams[i].pid) { - memcpy(data, clip->pg_streams[i].lang, 4); - return INPUT_OPTIONAL_SUCCESS; - } - } - } - - return INPUT_OPTIONAL_UNSUPPORTED; -} - -static int get_optional_data_impl (bluray_input_plugin_t *this, void *data, int data_type) -{ - switch (data_type) { - - case INPUT_OPTIONAL_DATA_DEMUXER: -#ifdef HAVE_CONFIG_H - *(const char **)data = "mpeg-ts"; -#else - *(const char **)data = "mpeg-ts-hdmv"; -#endif - return INPUT_OPTIONAL_SUCCESS; - - case INPUT_OPTIONAL_DATA_AUDIOLANG: - return get_audio_lang(this, data); - - case INPUT_OPTIONAL_DATA_SPULANG: - return get_spu_lang(this, data); - - default: - return INPUT_OPTIONAL_UNSUPPORTED; - } - - return INPUT_OPTIONAL_UNSUPPORTED; -} - -static int bluray_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - int r = INPUT_OPTIONAL_UNSUPPORTED; - - if (this && this->stream && data) { - pthread_mutex_lock(&this->title_info_mutex); - r = get_optional_data_impl(this, data, data_type); - pthread_mutex_unlock(&this->title_info_mutex); - } - - return r; -} - -static void bluray_plugin_dispose (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - - if (this->bdh) - bd_register_overlay_proc(this->bdh, NULL, NULL); - - close_overlay(this, -1); - - if (this->event_queue) - xine_event_dispose_queue(this->event_queue); - - pthread_mutex_lock(&this->title_info_mutex); - if (this->title_info) - bd_free_title_info(this->title_info); - this->title_info = NULL; - pthread_mutex_unlock(&this->title_info_mutex); - - pthread_mutex_destroy(&this->title_info_mutex); - - if (this->bdh) - bd_close(this->bdh); - - free (this->mrl); - free (this->disc_root); - free (this->disc_name); - - close_loop_device(this); - - free (this); -} - -static int parse_mrl(const char *mrl_in, char **path, int *title, int *chapter) -{ - int skip = 0; - - if (!strncasecmp(mrl_in, "bluray:", 7)) - skip = 7; - else if (!strncasecmp(mrl_in, "bd:", 3)) - skip = 3; - else - return -1; - - char *mrl = strdup(mrl_in + skip); - - /* title[.chapter] given ? parse and drop it */ - if (mrl[strlen(mrl)-1] != '/') { - char *end = strrchr(mrl, '/'); - if (end && end[1]) { - if (sscanf(end, "/%d.%d", title, chapter) < 1) - *title = -1; - else - *end = 0; - } - } - lprintf(" -> title %d, chapter %d, mrl \'%s\'\n", *title, *chapter, mrl); - - if ((mrl[0] == 0) || - (mrl[1] == 0 && mrl[0] == '/') || - (mrl[2] == 0 && mrl[1] == '/' && mrl[0] == '/') || - (mrl[3] == 0 && mrl[2] == '/' && mrl[1] == '/' && mrl[0] == '/')){ - - /* default device */ - *path = NULL; - - } else if (*mrl == '/') { - - /* strip extra slashes */ - char *start = mrl; - while (start[0] == '/' && start[1] == '/') - start++; - - *path = strdup(start); - - _x_mrl_unescape(*path); - - lprintf("non-defaut mount point \'%s\'\n", *path); - - } else { - lprintf("invalid mrl \'%s\'\n", mrl_in); - free(mrl); - return 0; - } - - free(mrl); - - return 1; -} - -static int get_disc_info(bluray_input_plugin_t *this) -{ - const BLURAY_DISC_INFO *disc_info; - - disc_info = bd_get_disc_info(this->bdh); - - if (!disc_info) { - LOGMSG("bd_get_disc_info() failed\n"); - return -1; - } - - if (!disc_info->bluray_detected) { - LOGMSG("bd_get_disc_info(): BluRay not detected\n"); - this->nav_mode = 0; - return 0; - } - - if (disc_info->aacs_detected && !disc_info->aacs_handled) { - if (!disc_info->libaacs_detected) - _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, - "Media stream scrambled/encrypted with AACS", - "libaacs not installed", NULL); - else - _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, - "Media stream scrambled/encrypted with AACS", NULL); - return -1; - } - - if (disc_info->bdplus_detected && !disc_info->bdplus_handled) { - if (!disc_info->libbdplus_detected) - _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, - "Media scrambled/encrypted with BD+", - "libbdplus not installed.", NULL); - else - _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, - "Media stream scrambled/encrypted with BD+", NULL); - return -1; - } - - if (this->nav_mode && !disc_info->first_play_supported) { - _x_message (this->stream, XINE_MSG_GENERAL_WARNING, - "Can't play disc in HDMV navigation mode", - "First Play title not supported", NULL); - this->nav_mode = 0; - } - - if (this->nav_mode && disc_info->num_unsupported_titles > 0) { - _x_message (this->stream, XINE_MSG_GENERAL_WARNING, - "Unsupported titles found", - "Some titles can't be played in navigation mode", NULL); - } - - this->num_titles = disc_info->num_hdmv_titles + disc_info->num_bdj_titles; - this->disc_info = disc_info; - - return 1; -} - -static char *get_file_name(const char *path) -{ - const char *name_start; - char *file_name = NULL; - int len; - - name_start = path + strlen(path) - 1; - /* skip trailing '/' */ - while (name_start > path && name_start[0] == '/') - name_start--; - /* find prev '/' */ - while (name_start > path && name_start[-1] != '/') - name_start--; - - file_name = strdup(name_start); - len = strlen(file_name); - - /* trim trailing '/' */ - while (len > 0 && file_name[len - 1] == '/') - file_name[--len] = 0; - - /* trim trailing ".iso" */ - if (len > 3 && !strcasecmp(file_name + len - 4, ".iso")) - file_name[len - 4] = 0; - - /* '_' --> ' ' */ - for (len = 0; file_name[len]; ++len) - if (file_name[len] == '_') - file_name[len] = ' '; - - lprintf("disc name: %s\n", file_name); - return file_name; -} - -static int is_iso_image(const char *mrl) -{ - if (mrl) { - const char *pos = strrchr(mrl, '.'); - return pos && !strcasecmp(pos + 1, "iso"); - } - return 0; -} - -static int bluray_plugin_open (input_plugin_t *this_gen) -{ - bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; - int title = -1; - int chapter = 0; - - lprintf("bluray_plugin_open '%s'\n",this->mrl); - - /* validate and parse mrl */ - if (!parse_mrl(this->mrl, &this->disc_root, &title, &chapter)) - return -1; - - if (!strncasecmp(this->mrl, "bd:", 3)) - this->nav_mode = 1; - - if (!this->disc_root) - this->disc_root = strdup(this->class->mountpoint); - - /* mount .iso image */ - if (is_iso_image(this->disc_root) && !mount_iso_image(this)) { - _x_message (this->stream, XINE_MSG_GENERAL_WARNING, - "Can't play BluRay .iso image", - "Mounting of .iso image using loop device failed.\n" - "Not enough loop devices or insufficient permissions ?", NULL); - return -1; - } - - /* open libbluray */ - - if (! (this->bdh = bd_open (this->disc_root, NULL))) { - LOGMSG("bd_open(\'%s\') failed: %s\n", this->disc_root, strerror(errno)); - return -1; - } - lprintf("bd_open(\'%s\') OK\n", this->disc_root); - - if (get_disc_info(this) < 0) { - return -1; - } - - /* load title list */ - - this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH); - LOGMSG("%d titles\n", this->num_title_idx); - - if (this->num_title_idx < 1) - return -1; - - /* select title */ - - /* if title was not in mrl, find the main title */ - if (title < 0) { - uint64_t duration = 0; - int i, playlist = 99999; - for (i = 0; i < this->num_title_idx; i++) { - BLURAY_TITLE_INFO *info = bd_get_title_info(this->bdh, i, 0); - if (info->duration > duration) { - title = i; - duration = info->duration; - playlist = info->playlist; - } - bd_free_title_info(info); - } - lprintf("main title: %d (%05d.mpls)\n", title, playlist); - } - - /* update player settings */ - - bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_REGION_CODE, this->class->region); - bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_PARENTAL, this->class->parental); - bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_AUDIO_LANG, this->class->language); - bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_PG_LANG, this->class->language); - bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_MENU_LANG, this->class->language); - bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_COUNTRY_CODE, this->class->country); - - /* init event queue */ - bd_get_event(this->bdh, NULL); - - /* get disc name */ - - this->meta_dl = bd_get_meta(this->bdh); - - if (this->meta_dl && this->meta_dl->di_name && strlen(this->meta_dl->di_name) > 1) { - this->disc_name = strdup(this->meta_dl->di_name); - } - else if (strcmp(this->disc_root, this->class->mountpoint)) { - this->disc_name = get_file_name(this->iso_image ?: this->disc_root); - } - - /* register overlay (graphics) handler */ - - bd_register_overlay_proc(this->bdh, this, overlay_proc); - - /* open */ - this->current_title = -1; - this->current_title_idx = -1; - - if (this->nav_mode) { - if (bd_play(this->bdh) <= 0) { - LOGMSG("bd_play() failed\n"); - return -1; - } - - } else { - if (open_title(this, title) <= 0 && - open_title(this, 0) <= 0) - return -1; - } - - /* jump to chapter */ - - if (chapter > 0) { - chapter = MAX(0, MIN((int)this->title_info->chapter_count, chapter) - 1); - bd_seek_chapter(this->bdh, chapter); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, chapter + 1); - } - - return 1; -} - -static input_plugin_t *bluray_class_get_instance (input_class_t *cls_gen, xine_stream_t *stream, - const char *mrl) -{ - bluray_input_plugin_t *this; - - lprintf("bluray_class_get_instance\n"); - - if (strncasecmp(mrl, "bluray:", 7) && strncasecmp(mrl, "bd:", 3)) - return NULL; - - this = (bluray_input_plugin_t *) calloc(1, sizeof (bluray_input_plugin_t)); - - this->stream = stream; - this->class = (bluray_input_class_t*)cls_gen; - this->mrl = strdup(mrl); - - this->cap_seekable = INPUT_CAP_SEEKABLE; - - this->input_plugin.open = bluray_plugin_open; - this->input_plugin.get_capabilities = bluray_plugin_get_capabilities; - this->input_plugin.read = bluray_plugin_read; - this->input_plugin.read_block = bluray_plugin_read_block; - this->input_plugin.seek = bluray_plugin_seek; - this->input_plugin.seek_time = bluray_plugin_seek_time; - this->input_plugin.get_current_pos = bluray_plugin_get_current_pos; - this->input_plugin.get_current_time = bluray_plugin_get_current_time; - this->input_plugin.get_length = bluray_plugin_get_length; - this->input_plugin.get_blocksize = bluray_plugin_get_blocksize; - this->input_plugin.get_mrl = bluray_plugin_get_mrl; - this->input_plugin.get_optional_data = bluray_plugin_get_optional_data; - this->input_plugin.dispose = bluray_plugin_dispose; - this->input_plugin.input_class = cls_gen; - - this->event_queue = xine_event_new_queue (this->stream); - - pthread_mutex_init(&this->title_info_mutex, NULL); - - this->pg_stream = -1; - - return &this->input_plugin; -} - -/* - * plugin class - */ - -static void mountpoint_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *this = (bluray_input_class_t *) data; - - this->mountpoint = cfg->str_value; -} - -static void device_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *this = (bluray_input_class_t *) data; - - this->device = cfg->str_value; -} - -static void language_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *class = (bluray_input_class_t *) data; - - class->language = cfg->str_value; -#if 0 - if (class->bdh) { - bd_set_player_setting_str(class->bdh, BLURAY_PLAYER_SETTING_AUDIO_LANG, class->language); - bd_set_player_setting_str(class->bdh, BLURAY_PLAYER_SETTING_PG_LANG, class->language); - bd_set_player_setting_str(class->bdh, BLURAY_PLAYER_SETTING_MENU_LANG, class->language); - } -#endif -} - -static void country_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *this = (bluray_input_class_t *) data; - - this->country = cfg->str_value; -} - -static void region_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *this = (bluray_input_class_t *) data; - - this->region = cfg->num_value; -} - -static void parental_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - bluray_input_class_t *this = (bluray_input_class_t *) data; - - this->parental = cfg->num_value; -} - -static void free_xine_playlist(bluray_input_class_t *this) -{ - if (this->xine_playlist) { - int i; - for (i = 0; i < this->xine_playlist_size; i++) { - MRL_ZERO(this->xine_playlist[i]); - free(this->xine_playlist[i]); - } - free(this->xine_playlist); - this->xine_playlist = NULL; - } - - this->xine_playlist_size = 0; -} - -#if INPUT_PLUGIN_IFACE_VERSION < 18 -static const char *bluray_class_get_description (input_class_t *this_gen) -{ - (void)this_gen; - - return _("BluRay input plugin"); -} -#endif - -#if INPUT_PLUGIN_IFACE_VERSION < 18 -static const char *bluray_class_get_identifier (input_class_t *this_gen) -{ - (void)this_gen; - - return "bluray"; -} -#endif - -static char **bluray_class_get_autoplay_list (input_class_t *this_gen, int *num_files) -{ - (void)this_gen; - - static char *autoplay_list[] = { "bluray:/", NULL }; - - *num_files = 1; - - return autoplay_list; -} - -static xine_mrl_t **bluray_class_get_dir(input_class_t *this_gen, const char *filename, int *nFiles) -{ - bluray_input_class_t *this = (bluray_input_class_t*) this_gen; - char *path = NULL; - int title = -1, chapter = -1, i, num_pl; - BLURAY *bdh; - - lprintf("bluray_class_get_dir(%s)\n", filename); - - free_xine_playlist(this); - - if (filename) - parse_mrl(filename, &path, &title, &chapter); - - bdh = bd_open(path ? path : this->mountpoint, NULL); - - if (bdh) { - num_pl = bd_get_titles(bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH); - - if (num_pl > 0) { - - this->xine_playlist_size = num_pl; - this->xine_playlist = calloc(this->xine_playlist_size + 1, sizeof(xine_mrl_t*)); - - for (i = 0; i < num_pl; i++) { - //BLURAY_TITLE_INFO *info = bd_get_title_info(bd, title); - - this->xine_playlist[i] = calloc(1, sizeof(xine_mrl_t)); - - if (asprintf(&this->xine_playlist[i]->origin, "bluray:/%s", path?:"") < 0) - this->xine_playlist[i]->origin = NULL; - if (asprintf(&this->xine_playlist[i]->mrl, "bluray:/%s/%d", path?:"", i) < 0) - this->xine_playlist[i]->mrl = NULL; - this->xine_playlist[i]->type = mrl_dvd; - //this->xine_playlist[i]->size = info->duration; - - //bd_free_title_info(info); - } - } - - bd_close(bdh); - } - - free(path); - - if (nFiles) - *nFiles = this->xine_playlist_size; - - return this->xine_playlist; -} - -static int bluray_class_eject_media (input_class_t *this_gen) -{ - (void)this_gen; -#if 0 - bluray_input_class_t *this = (bluray_input_class_t*) this_gen; - - return media_eject_media (this->xine, this->device); -#endif - return 1; -} - -static void bluray_class_dispose (input_class_t *this_gen) -{ - bluray_input_class_t *this = (bluray_input_class_t *) this_gen; - config_values_t *config = this->xine->config; - - free_xine_playlist(this); - - config->unregister_callback(config, "media.bluray.mountpoint"); - config->unregister_callback(config, "media.bluray.device"); - config->unregister_callback(config, "media.bluray.region"); - config->unregister_callback(config, "media.bluray.language"); - config->unregister_callback(config, "media.bluray.country"); - config->unregister_callback(config, "media.bluray.parental"); - - free (this); -} - -static void *bluray_init_plugin (xine_t *xine, void *data) -{ - (void)data; - - static char *skip_modes[] = {"skip chapter", "skip title", NULL}; - - config_values_t *config = xine->config; - bluray_input_class_t *this = (bluray_input_class_t *) calloc(1, sizeof (bluray_input_class_t)); - - this->xine = xine; - - this->input_class.get_instance = bluray_class_get_instance; -#if INPUT_PLUGIN_IFACE_VERSION < 18 - this->input_class.get_identifier = bluray_class_get_identifier; - this->input_class.get_description = bluray_class_get_description; -#else - this->input_class.identifier = "bluray"; - this->input_class.description = _("BluRay input plugin"); -#endif - this->input_class.get_dir = bluray_class_get_dir; - this->input_class.get_autoplay_list = bluray_class_get_autoplay_list; - this->input_class.dispose = bluray_class_dispose; - this->input_class.eject_media = bluray_class_eject_media; - - this->mountpoint = - config->register_filename(config, "media.bluray.mountpoint", - "/mnt/bluray", XINE_CONFIG_STRING_IS_DIRECTORY_NAME, - _("BluRay mount point"), - _("Default mount location for BluRay discs."), - 0, mountpoint_change_cb, (void *) this); - this->device = - config->register_filename(config, "media.bluray.device", - "/dev/dvd", XINE_CONFIG_STRING_IS_DIRECTORY_NAME, - _("device used for BluRay playback"), - _("The path to the device " - "which you intend to use for playing BluRy discs."), - 0, device_change_cb, (void *) this); - - /* Player settings */ - this->language = - config->register_string(config, "media.bluray.language", - "eng", - _("default language for BluRay playback"), - _("xine tries to use this language as a default for BluRay playback. " - "As far as the BluRay supports it, menus and audio tracks will be presented " - "in this language.\nThe value must be a three character" - "ISO639-2 language code."), - 0, language_change_cb, this); - this->country = - config->register_string(config, "media.bluray.country", - "en", - _("BluRay player country code"), - _("The value must be a two character ISO3166-1 country code."), - 0, country_change_cb, this); - this->region = - config->register_num(config, "media.bluray.region", - 7, - _("BluRay player region code (1=A, 2=B, 4=C)"), - _("This only needs to be changed if your BluRay jumps to a screen " - "complaining about a wrong region code. It has nothing to do with " - "the region code set in BluRay drives, this is purely software."), - 0, region_change_cb, this); - this->parental = - config->register_num(config, "media.bluray.parental", - 99, - _("parental control age limit (1-99)"), - _("Prevents playback of BluRay titles where parental " - "control age limit is higher than this limit"), - 0, parental_change_cb, this); - - /* */ - config->register_enum(config, "media.bluray.skip_behaviour", 0, - skip_modes, - _("unit for the skip action"), - _("You can configure the behaviour when issuing a skip command (using the skip " - "buttons for example)."), - 20, NULL, NULL); - - return this; -} - -/* - * exported plugin catalog entry - */ - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ -#if INPUT_PLUGIN_IFACE_VERSION <= 17 - { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 17, "BLURAY", XINE_VERSION_CODE, NULL, bluray_init_plugin }, - { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 17, "BD", XINE_VERSION_CODE, NULL, bluray_init_plugin }, -#elif INPUT_PLUGIN_IFACE_VERSION >= 18 - { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "BLURAY", XINE_VERSION_CODE, NULL, bluray_init_plugin }, - { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "BD", XINE_VERSION_CODE, NULL, bluray_init_plugin }, -#endif - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/xine/BluRay/xine_lpcm_decoder.c b/xine/BluRay/xine_lpcm_decoder.c deleted file mode 100644 index 719963fa..00000000 --- a/xine/BluRay/xine_lpcm_decoder.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2000-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * 31-8-2001 Added LPCM rate sensing. - * (c) 2001 James Courtier-Dutton James@superbug.demon.co.uk - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef __sun -#define _XOPEN_SOURCE 500 -#endif -/* avoid compiler warnings */ -#define _BSD_SOURCE 1 - -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <netinet/in.h> /* ntohs */ - -#ifdef HAVE_CONFIG_H -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" -#else -#include <xine/xine_internal.h> -#include <xine/audio_out.h> -#include <xine/buffer.h> -#endif - -#ifdef WIN32 -#include <winsock.h> -/*#include <Winsock2.h>*/ /* htons */ -#endif - -#ifndef EXPORTED -# define EXPORTED __attribute__((visibility("default"))) -#endif - -typedef struct { - audio_decoder_class_t decoder_class; -} lpcm_class_t; - -typedef struct lpcm_decoder_s { - audio_decoder_t audio_decoder; - - xine_stream_t *stream; - - uint32_t rate; - uint32_t bits_per_sample; - uint32_t number_of_channels; - uint32_t ao_cap_mode; - - int output_open; - int cpu_be; /* TRUE, if we're a Big endian CPU */ - - int64_t pts; - - uint8_t *buf; - size_t buffered_bytes; - size_t buf_size; - -} lpcm_decoder_t; - -static void lpcm_reset (audio_decoder_t *this_gen) { - - lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; - - free (this->buf); - this->buf = NULL; -} - -static void lpcm_discontinuity (audio_decoder_t *this_gen) { - - lpcm_reset(this_gen); -} - -static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { - - lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; - int16_t *sample_buffer=(int16_t *)buf->content; - int buf_size = buf->size; - int stream_be; - audio_buffer_t *audio_buffer; - int format_changed = 0; - int special_dvd_audio = 0; - - /* Drop preview data */ - if (buf->decoder_flags & BUF_FLAG_PREVIEW) - return; - - /* get config byte from mpeg2 stream */ - if ( (buf->decoder_flags & BUF_FLAG_SPECIAL) && - buf->decoder_info[1] == BUF_SPECIAL_LPCM_CONFIG ) { - unsigned int bits_per_sample = 16; - unsigned int sample_rate = 0; - unsigned int num_channels; - - lprintf("lpcm_decoder: config data 0x%x\n", buf->decoder_info[2]); - - /* BluRay PCM header is 4 bytes */ - if (buf->decoder_info[2] & 0xffffff00) { - static const uint8_t channels[16] = {0, 1, 0, 2, 3, 3, 4, 4, 5, 6, 7, 8, 0, 0, 0, 0}; - - num_channels = channels[(buf->decoder_info[2] >> (16+4)) & 0x0f]; - switch ((buf->decoder_info[2] >> (24+6)) & 0x03) { - case 1: bits_per_sample = 16; break; - case 2: /*bits_per_sample = 20; break;*/ - /* 20 bits = padded to 24 bits with four zero bits */ - case 3: bits_per_sample = 24; break; - default: bits_per_sample = 0; break; - } - switch ((buf->decoder_info[2] >> 16) & 0x0f) { - case 1: sample_rate = 48000; break; - case 4: sample_rate = 96000; break; - case 5: sample_rate = 192000; break; - default: sample_rate = 0; break; - } - - if (!num_channels || !sample_rate || !bits_per_sample) - xine_log (this->stream->xine, XINE_LOG_MSG, - "lpcm_decoder: unsupported BluRay PCM format: 0x%08x\n", buf->decoder_info[2]); - - if (this->buffered_bytes) - xine_log (this->stream->xine, XINE_LOG_MSG, "lpcm_decoder: %zd bytes lost !\n", this->buffered_bytes); - - if (!this->buf) { - this->buffered_bytes = 0; - this->buf_size = 8128; - this->buf = malloc(this->buf_size); - } - - } else { - - /* MPEG2/DVD PCM header is one byte */ - num_channels = (buf->decoder_info[2] & 0x7) + 1; - switch ((buf->decoder_info[2]>>4) & 3) { - case 0: sample_rate = 48000; break; - case 1: sample_rate = 96000; break; - case 2: sample_rate = 44100; break; - case 3: sample_rate = 32000; break; - } - switch ((buf->decoder_info[2]>>6) & 3) { - case 0: bits_per_sample = 16; break; - case 1: bits_per_sample = 20; break; - case 2: bits_per_sample = 24; special_dvd_audio = 1; break; - } - } - - if( this->bits_per_sample != bits_per_sample || - this->number_of_channels != num_channels || - this->rate != sample_rate || - !this->output_open ) { - this->bits_per_sample = bits_per_sample; - this->number_of_channels = num_channels; - this->rate = sample_rate; - format_changed++; - - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "lpcm_decoder: format changed to %d channels, %d bits per sample, %d Hz, %d kbit/s\n", - num_channels, bits_per_sample, sample_rate, (num_channels * sample_rate * bits_per_sample)/1024); - } - } - - if( buf->decoder_flags & BUF_FLAG_STDHEADER ) { - this->rate=buf->decoder_info[1]; - this->bits_per_sample=buf->decoder_info[2]; - this->number_of_channels=buf->decoder_info[3]; - format_changed++; - } - - /* - * (re-)open output device - */ - if ( format_changed ) { - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - - this->ao_cap_mode=_x_ao_channels2mode(this->number_of_channels); - - /* force 24-bit samples into 16 bits for now */ - if (this->bits_per_sample == 24) - this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, this->stream, - 16, - this->rate, - this->ao_cap_mode) ; - else - this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, this->stream, - this->bits_per_sample, - this->rate, - this->ao_cap_mode) ; - - /* stream/meta info */ - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "Linear PCM"); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, - this->bits_per_sample * this->rate * this->number_of_channels); - } - - if (!this->output_open || (buf->decoder_flags & BUF_FLAG_HEADER) ) - return; - - if (buf->pts && !this->pts) - this->pts = buf->pts; - - /* data accumulation */ - if (this->buf) { - int frame_end = buf->decoder_flags & BUF_FLAG_FRAME_END; - if (this->buffered_bytes || !frame_end) { - if (this->buf_size < this->buffered_bytes + buf->size) { - this->buf_size *= 2; - this->buf = realloc(this->buf, this->buf_size); - } - - memcpy(this->buf + this->buffered_bytes, buf->content, buf->size); - this->buffered_bytes += buf->size; - - if (!frame_end) - return; - - sample_buffer = (int16_t*)this->buf; - buf_size = this->buffered_bytes; - this->buffered_bytes = 0; - } - } - - audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); - - /* Swap LPCM samples into native byte order, if necessary */ - buf->type &= 0xffff0000; - stream_be = ( buf->type == BUF_AUDIO_LPCM_BE ); - - if( this->bits_per_sample == 16 ){ - if (stream_be != this->cpu_be) - swab (sample_buffer, audio_buffer->mem, buf_size); - else - memcpy (audio_buffer->mem, sample_buffer, buf_size); - } - else if( this->bits_per_sample == 20 ) { - uint8_t *s = (uint8_t *)sample_buffer; - uint8_t *d = (uint8_t *)audio_buffer->mem; - int n = buf_size; - - if (stream_be != this->cpu_be) { - while( n >= 0 ) { - swab( s, d, 8 ); - s += 10; - d += 8; - n -= 10; - } - } else { - while( n >= 0 ) { - memcpy( d, s, 8 ); - s += 10; - d += 8; - n -= 10; - } - } - } else if( this->bits_per_sample == 24 ) { - uint8_t *s = (uint8_t *)sample_buffer; - uint8_t *d = (uint8_t *)audio_buffer->mem; - int n = buf_size; - - if ( stream_be ) { - if (special_dvd_audio) - while (n >= 12) { - if ( stream_be == this->cpu_be ) { - *d++ = s[0]; - *d++ = s[1]; - *d++ = s[2]; - *d++ = s[3]; - *d++ = s[4]; - *d++ = s[5]; - *d++ = s[6]; - *d++ = s[7]; - } else { - *d++ = s[1]; - *d++ = s[0]; - *d++ = s[3]; - *d++ = s[2]; - *d++ = s[5]; - *d++ = s[4]; - *d++ = s[7]; - *d++ = s[6]; - } - s += 12; - n -= 12; - } - else - while (n >= 3) { - if ( stream_be == this->cpu_be ) { - *d++ = s[0]; - *d++ = s[1]; - } else { - *d++ = s[1]; - *d++ = s[0]; - } - s += 3; - n -= 3; - } - } else { - while (n >= 3) { - if ( stream_be == this->cpu_be ) { - *d++ = s[1]; - *d++ = s[2]; - } else { - *d++ = s[2]; - *d++ = s[1]; - } - s += 3; - n -= 3; - } - } - - if ( (d - (uint8_t*)audio_buffer->mem)/2*3 < buf_size ) - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "lpcm_decoder: lost %i bytes of %i in the buffer\n", (int)(buf_size - (d - (uint8_t*)audio_buffer->mem)/2*3), buf_size); - - } else { - memcpy (audio_buffer->mem, sample_buffer, buf_size); - } - - audio_buffer->vpts = this->pts; - audio_buffer->num_frames = (((buf_size*8)/this->number_of_channels)/this->bits_per_sample); - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - this->pts = 0; -} - -static void lpcm_dispose (audio_decoder_t *this_gen) { - lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; - - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - this->output_open = 0; - - free (this->buf); - - free (this_gen); -} - -static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { - - lpcm_decoder_t *this ; - - this = (lpcm_decoder_t *) calloc(1, sizeof(lpcm_decoder_t)); - - this->audio_decoder.decode_data = lpcm_decode_data; - this->audio_decoder.reset = lpcm_reset; - this->audio_decoder.discontinuity = lpcm_discontinuity; - this->audio_decoder.dispose = lpcm_dispose; - - this->output_open = 0; - this->rate = 0; - this->bits_per_sample=0; - this->number_of_channels=0; - this->ao_cap_mode=0; - this->stream = stream; - - this->cpu_be = ( htons(1) == 1 ); - - return &this->audio_decoder; -} - -static char *get_identifier (audio_decoder_class_t *this) { - return "Linear PCM (BluRay)"; -} - -static char *get_description (audio_decoder_class_t *this) { - return "Linear PCM audio decoder plugin (BluRay)"; -} - -static void dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - - lpcm_class_t *this ; - - this = (lpcm_class_t *) calloc(1, sizeof(lpcm_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; - - return this; -} - -static uint32_t audio_types[] = { - BUF_AUDIO_LPCM_BE, BUF_AUDIO_LPCM_LE, 0 -}; - -static const decoder_info_t dec_info_audio = { - audio_types, /* supported types */ - 10 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_DECODER, 15, "pcm_bluray", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; |