diff options
author | cvs2svn <admin@example.com> | 2009-10-21 00:02:02 +0000 |
---|---|---|
committer | cvs2svn <admin@example.com> | 2009-10-21 00:02:02 +0000 |
commit | 97a97ca3358eb48de3eb7a222e487e800566569f (patch) | |
tree | 97c920d0225a1c9773a3bce2207f261d7d230123 /xine | |
parent | a61961358c5a2ec92340b3f8e056bab55438f103 (diff) | |
download | xineliboutput-CVS.tar.gz xineliboutput-CVS.tar.bz2 |
This commit was manufactured by cvs2svn to create branch 'CVS'.CVS
Diffstat (limited to 'xine')
-rw-r--r-- | xine/BluRay/Makefile | 33 | ||||
-rw-r--r-- | xine/BluRay/decode_spuhdmv.c | 1027 | ||||
-rw-r--r-- | xine/BluRay/demux_ts.c | 2504 | ||||
-rw-r--r-- | xine/adjustable_scr.c | 309 | ||||
-rw-r--r-- | xine/adjustable_scr.h | 37 | ||||
-rw-r--r-- | xine/demux_xvdr.c | 1234 | ||||
-rw-r--r-- | xine/demux_xvdr_tsdata.c | 91 | ||||
-rw-r--r-- | xine/demux_xvdr_tsdata.h | 34 | ||||
-rw-r--r-- | xine/osd_manager.c | 729 | ||||
-rw-r--r-- | xine/osd_manager.h | 36 | ||||
-rw-r--r-- | xine/post.c | 901 | ||||
-rw-r--r-- | xine/post.h | 99 | ||||
-rw-r--r-- | xine/post_util.h | 144 | ||||
-rw-r--r-- | xine/ts2es.c | 284 | ||||
-rw-r--r-- | xine/ts2es.h | 21 | ||||
-rw-r--r-- | xine/vo_hook.c | 201 | ||||
-rw-r--r-- | xine/vo_hook.h | 42 | ||||
-rw-r--r-- | xine/vo_osdreorder.c | 100 | ||||
-rw-r--r-- | xine/vo_osdreorder.h | 16 | ||||
-rw-r--r-- | xine/vo_osdscaler.c | 439 | ||||
-rw-r--r-- | xine/vo_osdscaler.h | 16 | ||||
-rw-r--r-- | xine/vo_post.h | 25 | ||||
-rw-r--r-- | xine/vo_props.h | 60 | ||||
-rw-r--r-- | xine/xvdr_metronom.c | 164 | ||||
-rw-r--r-- | xine/xvdr_metronom.h | 49 |
25 files changed, 0 insertions, 8595 deletions
diff --git a/xine/BluRay/Makefile b/xine/BluRay/Makefile deleted file mode 100644 index 531449c6..00000000 --- a/xine/BluRay/Makefile +++ /dev/null @@ -1,33 +0,0 @@ - -XINEDMXPLUGIN = xineplug_dmx_mpeg_ts_hdmv.so -OBJS_XINEDMXPLUGIN = demux_ts.o -XINESPUPLUGIN = xineplug_decode_spuhdmv.so -OBJS_XINESPUPLUGIN = decode_spuhdmv.o - -LIBS_XINE = $(shell pkg-config libxine --libs) -CFLAGS += $(shell pkg-config libxine --cflags) -CFLAGS += -Ixine -CFLAGS += -O2 -fPIC -XINEPLUGINDIR = $(shell pkg-config libxine --variable=plugindir) -DESTDIR = / -INSTALL = install -LDFLAGS += -shared -fvisibility=hidden - -all: $(XINEDMXPLUGIN) $(XINESPUPLUGIN) - -$(XINEDMXPLUGIN): $(OBJS_XINEDMXPLUGIN) - $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS_XINE) -o $@ $(OBJS_XINEDMXPLUGIN) - -$(XINESPUPLUGIN): $(OBJS_XINESPUPLUGIN) - $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS_XINE) -o $@ $(OBJS_XINESPUPLUGIN) - -clean: - @rm -rf *.o *.so *~ - -install: all - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) - @$(INSTALL) -m 0644 $(XINEDMXPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEDMXPLUGIN) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) - @$(INSTALL) -m 0644 $(XINESPUPLUGIN) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINESPUPLUGIN) diff --git a/xine/BluRay/decode_spuhdmv.c b/xine/BluRay/decode_spuhdmv.c deleted file mode 100644 index 81ac6778..00000000 --- a/xine/BluRay/decode_spuhdmv.c +++ /dev/null @@ -1,1027 +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 TRACE(x...) printf(x) -/*#define TRACE(x...) */ -#define ERROR(x...) fprintf(stderr, "spuhdmv: " x) -/*#define ERROR(x...) lprintf(x) */ - -#ifndef EXPORTED -# define EXPORTED __attribute__((visibility("default"))) -#endif - -#ifndef BUF_SPU_HDMV -# define BUF_SPU_HDMV 0x04180000 -#endif - -/* - * 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; - - rle_elem_t *rle; - uint num_rle; - size_t data_size; - -#if 0 - uint8_t *raw_data; /* partial RLE data in HDMV format */ - size_t raw_data_len; - size_t raw_data_size; -#endif - - 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; - uint8_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 { \ - uint 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(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)) { - 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 >= 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); - - TRACE(" skip_segment: %d bytes left\n", (uint)buf->len); - } else { - ERROR(" skip_segment: ERROR - %d bytes queued, %d required\n", - (uint)buf->len, buf->segment_len); - segbuf_reset (buf); - } -} - -/* - * access segment data - */ - -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]; - ERROR("segbuf_get_u8: read failed (end of segment reached) !"); - 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); -} - -uint8_t *segbuf_get_string(segment_buffer_t *buf, size_t len) -{ - if (len > 0) { - uint8_t *val = buf->segment_data; - buf->segment_data += len; - if (buf->segment_data <= buf->segment_end) - return val; - } - ERROR("segbuf_get_string(%d): read failed (end of segment reached) !", (int)len); - buf->error = 1; - return NULL; -} - -/* - * 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; - int i; - - if (buf->error) - return NULL; - - if (len % 5) { - ERROR(" decode_palette: segment size error (%d ; expected %d for %d entries)\n", - (uint)len, (uint)(5 * entries), (uint)entries); - return NULL; - } - TRACE("decode_palette: %d items (id %d, version %d)\n", - (uint)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) -{ - uint8_t object_id = segbuf_get_u16(buf); - uint8_t version = segbuf_get_u8 (buf); - uint8_t seq_desc = segbuf_get_u8 (buf); - - TRACE(" decode_object: object_id %d, version %d, seq 0x%x\n", - object_id, version, seq_desc); - - //LIST_FIND(); - subtitle_object_t *obj = calloc(1, sizeof(subtitle_object_t)); - obj->id = object_id; - - if (seq_desc & 0x80) { - - uint32_t data_len = segbuf_get_u24(buf); - obj->width = segbuf_get_u16(buf); - obj->height = segbuf_get_u16(buf); - - TRACE(" object length %d bytes, size %dx%d\n", data_len, obj->width, obj->height); - - segbuf_decode_rle (buf, obj); - - if (buf->error) { - free_subtitle_object(obj); - return NULL; - } - - } else { - ERROR(" TODO: APPEND RLE, length %d bytes\n", buf->segment_len - 4); - /* TODO */ - free_subtitle_object(obj); - return NULL; - } - - return obj; -} - -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); - - 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); - - 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); - - 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; - } - - 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); - - 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 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); - 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; - - /* 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, uint 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 = {0}; - vo_overlay_t overlay = {0}; - - /* find palette */ - subtitle_clut_t *clut = this->cluts; - while (clut && clut->id != palette_id_ref) - clut = clut->next; - if (!clut) { - 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) { - TRACE(" show_overlay: object %d not found !\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) { - 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; - - 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 = {0}; - int i = 0; - - while (this->overlay_handles[i] >= 0) { - 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->comp_descr.state) { - - /* 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) { - 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 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 void decode_segment(spuhdmv_decoder_t *this) -{ - TRACE("*** new segment, pts %010ld: 0x%02x (%8d bytes)", - this->pts, (uint)this->buf->segment_type, (uint)this->buf->segment_len); - - switch (this->buf->segment_type) { - case 0x14: - TRACE(" segment: PALETTE\n"); - decode_palette(this); - break; - case 0x15: - TRACE(" segment: OBJECT\n"); - decode_object(this); - break; - case 0x16: - TRACE(" segment: PRESENTATION SEGMENT\n"); - decode_presentation_segment(this); - break; - case 0x17: - TRACE(" segment: WINDOW DEFINITION\n"); - decode_window_definition(this); - break; - case 0x18: - TRACE(" segment: INTERACTIVE\n"); - break; - case 0x80: - TRACE(" segment: END OF DISPLAY\n"); - /* drop all cached objects */ - free_objs(this); - break; - default: - ERROR(" segment type 0x%x unknown, skipping\n", this->buf->segment_type); - break; - } - if (this->buf->error) { - 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 44d3ee88..00000000 --- a/xine/BluRay/demux_ts.c +++ /dev/null @@ -1,2504 +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 0x04180000 -#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 - - 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_AUDIO_PRIMARY_DTS_HDMV = 0x86, - STREAM_SPU_BITMAP_HDMV = 0x90, - - STREAM_VIDEO_VC1 = 0xea, /* VC-1 */ - STREAM_VIDEO_SMTPE_VC1 = 0xeb, /* SMTPE VC-1 */ - } streamType; - -#define WRAP_THRESHOLD 270000 - -#define PTS_AUDIO 0 -#define PTS_VIDEO 1 - -#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?) */ - int64_t packet_count; - int corrupted_pes; - uint32_t buffered_bytes; - int autodetected; - -} demux_ts_media; - -/* DVBSUB */ -#define MAX_SPU_LANGS 16 - -typedef struct { - spu_dvb_descriptor_t desc; - int pid; - int media_index; -} demux_ts_spu_lang; - -/* Audio Channels */ -#define MAX_AUDIO_TRACKS 16 - -typedef struct { - 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 blockSize; - int rate; - int media_num; - demux_ts_media media[MAX_PIDS]; - 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 programNumber; - unsigned int pcrPid; - unsigned int pid; - unsigned int pid_count; - unsigned int videoPid; - unsigned int videoMedia; - - demux_ts_audio_track audio_tracks[MAX_AUDIO_TRACKS]; - int audio_tracks_count; - - int send_end_buffers; - 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 */ - - int numPreview; - -} 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_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 ); -} - -/* - * 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); -} - -/* - * 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 - - /* - * Process all programs in the program loop. - */ - program_count = 0; - for (program = pkt + 13; - program < pkt + 13 + section_length - 9; - 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; - - /* - * If we have yet to learn our program number, then learn it, - * use this loop to eventually add support for dynamically changing - * PATs. - */ - program_count = 0; - - while ((this->program_number[program_count] != INVALID_PROGRAM) && - (this->program_number[program_count] != program_number) && - (program_count+1 < MAX_PMTS ) ) { - program_count++; - } - this->program_number[program_count] = program_number; - - /* 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->pmt_pid[program_count] = pmt_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 - } -} - -static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, - uint8_t *buf, int packet_len, - xine_stream_t *stream) { - - unsigned char *p; - uint32_t header_len; - int64_t pts; - uint32_t stream_id; - int pkt_len; - - p = buf; - pkt_len = packet_len; - - /* 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 -= 6; - /* packet_len = p[4] << 8 | p[5]; */ - stream_id = p[3]; - - if (packet_len==0) - { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: error pes length 0\n"); - 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 */ - - 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; - - header_len = p[8]; - - /* sometimes corruption on header_len causes segfault in memcpy below */ - if (header_len + 9 > pkt_len) { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len); - return 0; - } - - p += header_len + 9; - packet_len -= header_len + 3; - - 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 == STREAM_SPU_BITMAP_HDMV) { - 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 == STREAM_AUDIO_AC3) || /* ac3 - raw */ - (p[0] == 0x0B && p[1] == 0x77)) { /* ac3 - syncword */ - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_A52; - return 1; - - } else if (m->descriptor_tag == STREAM_AUDIO_PRIMARY_DTS_HDMV) { - m->content = p; - m->size = packet_len; - m->type |= BUF_AUDIO_DTS; - 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] & 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) { - - m->content = p+4; - m->size = packet_len - 4; - m->type |= BUF_AUDIO_A52; - return 1; - - } else if ((p[0]&0xf0) == 0xa0) { - - 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; - } - } - - m->content = p+pcm_offset; - m->size = packet_len-pcm_offset; - m->type |= BUF_AUDIO_LPCM_BE; - return 1; - } - - } else if ((stream_id >= 0xbc) && ((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: - case ISO_14496_PART3_AUDIO: - lprintf ("demux_ts: found AAC audio track.\n"); - m->type |= BUF_AUDIO_AAC; - 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 ; -} - - -/* - * 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 */ - - if (m->buffered_bytes) { - m->buf->content = m->buf->mem; - m->buf->size = m->buffered_bytes; - m->buf->type = m->type; - if( (m->buf->type & 0xffff0000) == BUF_SPU_DVD ) { - m->buf->decoder_flags |= BUF_FLAG_SPECIAL; - m->buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; - m->buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; - } - else { - if (this->numPreview<5) - ++this->numPreview; - if ( this->numPreview==1 ) - m->buf->decoder_flags=BUF_FLAG_HEADER | BUF_FLAG_FRAME_END; - else if ( this->numPreview<5 ) - m->buf->decoder_flags=BUF_FLAG_PREVIEW; - else - m->buf->decoder_flags=BUF_FLAG_FRAME_END; - } - m->buf->pts = m->pts; - m->buf->decoder_info[0] = 1; - - if( this->input->get_length (this->input) ) - m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * - 65535 / this->input->get_length (this->input) ); - if (this->rate) - m->buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) - * 1000 / (this->rate * 50)); - m->fifo->put(m->fifo, m->buf); - m->buffered_bytes = 0; - m->buf = NULL; /* forget about buf -- not our responsibility anymore */ -#ifdef TS_LOG - printf ("demux_ts: produced buffer, pts=%lld\n", m->pts); -#endif - } - /* 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, this->stream)) { - m->buf->free_buffer(m->buf); - m->buf = NULL; - - if (m->corrupted_pes > CORRUPT_PES_THRESHOLD && m->autodetected) { - if (this->videoPid == m->pid) { - this->videoPid = INVALID_PID; - this->last_pmt_crc = 0; - } - } else { - 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->buffered_bytes = m->size; - } - - } else if (!m->corrupted_pes) { /* no pus -- PES packet continuation */ - - if ((m->buffered_bytes + len) > MAX_PES_BUF_SIZE) { - m->buf->content = m->buf->mem; - m->buf->size = m->buffered_bytes; - m->buf->type = m->type; - m->buf->pts = m->pts; - m->buf->decoder_info[0] = 1; - if( this->input->get_length (this->input) ) - m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * - 65535 / this->input->get_length (this->input) ); - if (this->rate) - m->buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) - * 1000 / (this->rate * 50)); - - m->fifo->put(m->fifo, m->buf); - m->buffered_bytes = 0; - m->buf = m->fifo->buffer_pool_alloc(m->fifo); - -#ifdef TS_LOG - printf ("demux_ts: produced buffer, pts=%lld\n", m->pts); -#endif - - } - memcpy(m->buf->mem + m->buffered_bytes, ts, len); - m->buffered_bytes += 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; - m->buffered_bytes = 0; -} - - -/* 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] == 10 && 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] == 5 && 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; -} - - -/* - * 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; - - if (this->pmt[program_count] != NULL) 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 = 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) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { -#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); - 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] == 0x6a) && (this->audio_tracks_count < MAX_AUDIO_TRACKS)) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { -#ifdef TS_PMT_LOG - printf ("demux_ts: PMT AC3 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_AUDIO_AC3); - - 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); - this->audio_tracks_count++; - break; - } - } - /* Teletext */ - else if (stream[i] == 0x56) - { -#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] == 0x59) - { - 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 STREAM_SPU_BITMAP_HDMV: - if (this->hdmv > 0) { - if (pid >= 0x1200 && pid < 0x1300) { - /* HDMV Presentation Graphics / SPU */ - 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) ) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { - 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)) { - 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); - 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->pcrPid != pid) { -#ifdef TS_PMT_LOG - if (this->pcrPid == 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->pcrPid = pid; - } - - if ( this->stream->spu_channel>=0 && this->spu_langs_count>0 ) - demux_ts_update_spu_channel( 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, - &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; - if ( (this->packet_number) >= this->npkt_read) { - - /* NEW: handle read returning less packets than NPKT_PER_READ... */ - do { - read_length = this->input->read(this->input, 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) { - - uint32_t discontinuity_indicator=0; - uint32_t random_access_indicator=0; - uint32_t elementary_stream_priority_indicator=0; - uint32_t PCR_flag=0; - int64_t PCR=0; - 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; - uint32_t offset = 1; - - discontinuity_indicator = ((data[0] >> 7) & 0x01); - random_access_indicator = ((data[0] >> 6) & 0x01); - elementary_stream_priority_indicator = ((data[0] >> 5) & 0x01); - PCR_flag = ((data[0] >> 4) & 0x01); - 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); - -#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) { - 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); - - EPCR = ((data[offset+4] & 0x1) << 8) | data[offset+5]; -#ifdef TS_LOG - printf ("demux_ts: PCR: %lld, EPCR: %u\n", - PCR, EPCR); -#endif - offset+=6; - } - if(OPCR_flag) { - 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]; -#ifdef TS_LOG - printf ("demux_ts: OPCR: %u, EOPCR: %u\n", - OPCR,EOPCR); -#endif - offset+=6; - } -#ifdef TS_LOG - 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 - return PCR; -} - -/* 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; -} - -/* 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; - 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; - } - 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) { - demux_ts_adaptation_field_parse (originalPkt+5, adaptation_field_length); - } - /* - * Skip adaptation header. - */ - data_offset += adaptation_field_length + 1; - } - - if (! (adaptation_field_control & 0x1)) { - return; - } - - data_len = PKT_SIZE - data_offset; - - /* - * audio/video pid auto-detection, if necessary - */ - program_count=0; - if(this->media_num<MAX_PMTS) - 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++; - } - - if (payload_unit_start_indicator && this->media_num < MAX_PIDS){ - int pes_stream_id; - if (pid == 0) { - demux_ts_parse_pat (this, originalPkt, originalPkt+data_offset-4, - payload_unit_start_indicator); - return; - } - program_count = 0; - pes_stream_id = originalPkt[data_offset+3]; - -#ifdef TS_HEADER_LOG - printf("demux_ts:ts_pes_header:stream_id=0x%.2x\n",pes_stream_id); -#endif - - if ( (pes_stream_id >= VIDEO_STREAM_S) && (pes_stream_id <= VIDEO_STREAM_E) ) { - if ( this->videoPid == INVALID_PID) { - int i, found = 0; - for(i = 0; i < this->media_num; i++) { - if (this->media[i].pid == pid) { - found = 1; - break; - } - } - - if (found && (this->media[i].corrupted_pes == 0)) { - this->videoPid = pid; - this->videoMedia = i; - } else if (!found) { - this->videoPid = pid; - this->videoMedia = this->media_num; - this->media[this->videoMedia].autodetected = 1; - demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, 0x100 + pes_stream_id); - } - - if (this->videoPid != INVALID_PID) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: auto-detected video pid 0x%.4x\n", pid); - } - } - } else if ( (pes_stream_id >= AUDIO_STREAM_S) && (pes_stream_id <= AUDIO_STREAM_E) ) { - if (this->audio_tracks_count < MAX_AUDIO_TRACKS) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { -#ifdef TS_PMT_LOG - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: auto-detected audio pid 0x%.4x\n", pid); -#endif - /* store PID, index and stream no. */ - 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_pes_new(this, this->media_num++, pid, - this->audio_fifo, 0x100 + pes_stream_id); - this->audio_tracks_count++; - } - } - } - } - - 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_PIDS_CHANGE: - - 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; - _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->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->send_end_buffers = 1; - 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_time /= 1000; - 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)) { - start_pos = start_time; - start_pos *= this->rate; - start_pos *= 50; - } - 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; - m->buffered_bytes = 0; - } - - if( !playing ) { - - this->status = DEMUX_OK; - this->buf_flag_seek = 0; - - } else { - - this->buf_flag_seek = 1; - _x_demux_flush_engine(this->stream); - - } - - 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 * 50)); - else - return 0; -} - - -static uint32_t demux_ts_get_capabilities(demux_plugin_t *this_gen) -{ - return DEMUX_CAP_AUDIOLANG | DEMUX_CAP_SPULANG; -} - -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; - int channel = *((int *)data); - - /* be a bit paranoid */ - if (this == NULL || this->stream == NULL) - return DEMUX_OPTIONAL_UNSUPPORTED; - - 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 - sprintf(str, "%3i", channel); - } - 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 - sprintf(str, "%3i", channel); - } - 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, int ts_size) -{ - int i, j; - int try_again, ts_detected = 0; - size_t 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 - ts_detected = 1; - } - } - } - - return ts_detected; -} - -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; - - switch (stream->content_detection_method) { - - case METHOD_BY_CONTENT: { - uint8_t buf[2069]; - - if (!_x_demux_read_header(input, buf, sizeof(buf))) - return NULL; - - if (detect_ts(buf, sizeof(buf), PKT_SIZE)) - hdmv = 0; - else if (detect_ts(buf, sizeof(buf), PKT_SIZE+4)) - hdmv = 1; - else - return NULL; - } - break; - - case METHOD_BY_EXTENSION: { - const char *const mrl = input->get_mrl (input); - - if (_x_demux_check_extension (mrl, "m2ts mts")) - hdmv = 1; - else - hdmv = 0; - - /* check extension */ - const char *const extensions = class_gen->get_extensions (class_gen); - - 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; - - 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->blockSize = PKT_SIZE; - - 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. - */ - for (i = 0; i < MAX_PIDS; i++) { - this->media[i].pid = INVALID_PID; - this->media[i].buf = NULL; - this->media[i].autodetected = 0; - } - - 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->programNumber = INVALID_PROGRAM; - this->pcrPid = INVALID_PID; - this->scrambled_npids = 0; - this->videoPid = INVALID_PID; - this->audio_tracks_count = 0; - this->last_pmt_crc = 0; - - this->rate = 16000; /* FIXME */ - - 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; - - this->numPreview=0; - - return &this->demux_plugin; -} - -/* - * ts demuxer class - */ - -static const char *get_description (demux_class_t *this_gen) { - return "MPEG Transport Stream demuxer"; -} - -static const char *get_identifier (demux_class_t *this_gen) { - return "MPEG_TS_HDMV"; -} - -static const char *get_extensions (demux_class_t *this_gen) { - return "m2ts mts"; -} - -static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; -} - -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; - this->demux_class.get_description = get_description; - this->demux_class.get_identifier = get_identifier; - this->demux_class.get_mimetypes = get_mimetypes; - this->demux_class.get_extensions = get_extensions; - this->demux_class.dispose = class_dispose; - - return this; -} - - -/* - * exported plugin catalog entry - */ -static const demuxer_info_t demux_info_ts = { - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_DEMUX, 26, "mpeg-ts-hdmv", XINE_VERSION_CODE, &demux_info_ts, init_class }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - diff --git a/xine/adjustable_scr.c b/xine/adjustable_scr.c deleted file mode 100644 index 4301e348..00000000 --- a/xine/adjustable_scr.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * adjustable_scr.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: adjustable_scr.c,v 1.2 2008-12-14 01:21:20 phintuka Exp $ - * - */ - - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/metronom.h> - -#include "adjustable_scr.h" - -/* - * SCR code is mostly copied from xine-lib (src/input/input_pvr.c) - * - * - * Copyright (C) 2000-2005 the xine project - * March 2003 - Miguel Freitas - * This plugin was sponsored by 1Control - * - * 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 - * - */ - -typedef struct scr_impl_s scr_impl_t; - -struct scr_impl_s { - union { - scr_plugin_t scr; - adjustable_scr_t ascr; - }; - - xine_t *xine; - - struct timeval cur_time; - int64_t cur_pts; - int xine_speed; - int scr_speed_base; - double speed_factor; - double speed_tuning; - - pthread_mutex_t lock; - - struct timeval last_time; -}; - -/* Only call set_pivot when already mutex locked ! */ -static void set_pivot (scr_impl_t *this) -{ - struct timeval tv; - int64_t pts; - double pts_calc; - - xine_monotonic_clock(&tv,NULL); - - pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor; - pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6; - pts = this->cur_pts + pts_calc; - - /* This next part introduces a one off inaccuracy - * to the scr due to rounding tv to pts. - */ - this->cur_time.tv_sec=tv.tv_sec; - this->cur_time.tv_usec=tv.tv_usec; - this->cur_pts=pts; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - return ; -} - -/* - * xine interface (scr_plugin_t) - */ - -static int scr_get_priority (scr_plugin_t *scr) -{ - return 50; /* high priority */ -} - -static int scr_set_fine_speed (scr_plugin_t *scr, int speed) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->xine_speed = speed; - this->speed_factor = (double) speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); - - return speed; -} - -static void scr_adjust (scr_plugin_t *scr, int64_t vpts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - struct timeval tv; - - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&tv,NULL); - this->cur_time.tv_sec=tv.tv_sec; - this->cur_time.tv_usec=tv.tv_usec; - this->cur_pts = vpts; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - pthread_mutex_unlock (&this->lock); -} - -static void scr_start (scr_plugin_t *scr, int64_t start_vpts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&this->cur_time, NULL); - this->cur_pts = start_vpts; - - this->last_time.tv_sec = this->cur_time.tv_sec; - this->last_time.tv_usec = this->cur_time.tv_usec; - - pthread_mutex_unlock (&this->lock); - - scr_set_fine_speed (&this->scr, XINE_FINE_SPEED_NORMAL); -} - -static int64_t scr_get_current (scr_plugin_t *scr) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - struct timeval tv; - int64_t pts; - double pts_calc; - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&tv,NULL); - - pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor; - pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6; - - pts = this->cur_pts + pts_calc; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - pthread_mutex_unlock (&this->lock); - - return pts; -} - -static void scr_exit (scr_plugin_t *scr) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_destroy (&this->lock); - free(this); -} - -/* - * adjusteble_scr_t - */ - -/* - * speed_tuning() - * - * - fine-tune SCR speed. Actual speed is base_speed * factor. - */ -static void adjustable_scr_speed_tuning (adjustable_scr_t *scr, double factor) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->speed_tuning = factor; - this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); -} - -/* - * speed_base() - * - * - set base speed of SCR (default is 90kHz) - */ -static void adjustable_scr_speed_base (adjustable_scr_t *scr, int hz) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->scr_speed_base = hz; - this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); -} - -/* - * jump() - * - * - Move SCR 'pts' ticks forward - */ -static void adjustable_scr_jump (adjustable_scr_t *scr, int pts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->cur_pts += pts; - - pthread_mutex_unlock (&this->lock); -} - -/* - * dispose() - * - * - unregister, stop and free resources - */ -static void adjustable_scr_dispose(adjustable_scr_t *scr) -{ - scr_impl_t *this = (scr_impl_t*)scr; - - /* unregister */ - if (this->xine) - this->xine->clock->unregister_scr(this->xine->clock, &this->scr); - - /* exit and dispose */ - this->scr.exit(&this->scr); -} - -/* - * adjusteble_scr_start() - * - */ -adjustable_scr_t* adjustable_scr_start (xine_t *xine) -{ - scr_impl_t *this; - - this = calloc(1, sizeof(scr_impl_t)); - - /* xine scr plugin interface */ - this->scr.interface_version = 3; - this->scr.set_fine_speed = scr_set_fine_speed; - this->scr.get_priority = scr_get_priority; - this->scr.adjust = scr_adjust; - this->scr.start = scr_start; - this->scr.get_current = scr_get_current; - this->scr.exit = scr_exit; - - /* tuning / management interface */ - this->ascr.set_speed_tuning = adjustable_scr_speed_tuning; - this->ascr.set_speed_base = adjustable_scr_speed_base; - this->ascr.jump = adjustable_scr_jump; - this->ascr.dispose = adjustable_scr_dispose; - - /* initialize */ - - pthread_mutex_init (&this->lock, NULL); - - this->xine = xine; - this->scr_speed_base = 90000; - - adjustable_scr_speed_tuning(&this->ascr, 1.0 ); - scr_set_fine_speed (&this->scr, XINE_SPEED_PAUSE); - - /* start and register */ - - uint64_t time = xine->clock->get_current_time(xine->clock); - this->scr.start(&this->scr, time); - - if (xine->clock->register_scr(xine->clock, &this->scr)) { - scr_exit(&this->scr); - return NULL; - } - - return &this->ascr; -} diff --git a/xine/adjustable_scr.h b/xine/adjustable_scr.h deleted file mode 100644 index 61707684..00000000 --- a/xine/adjustable_scr.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * adjustable_scr.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: adjustable_scr.h,v 1.1 2008-12-03 22:50:04 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_ADJUSTABLE_SCR_H_ -#define XINELIBOUTPUT_ADJUSTABLE_SCR_H_ - -/******************************* SCR ************************************* - * - * unix System Clock Reference + fine tuning - * - * fine tuning is used to change playback speed in live mode - * to keep in sync with mpeg source - *************************************************************************/ - -typedef struct adjustable_scr_s adjustable_scr_t; - -struct adjustable_scr_s { - scr_plugin_t scr; - - void (*set_speed_tuning)(adjustable_scr_t *this, double factor); - void (*set_speed_base) (adjustable_scr_t *this, int hz); - void (*jump) (adjustable_scr_t *this, int pts); - - void (*dispose) (adjustable_scr_t *this); -}; - -adjustable_scr_t *adjustable_scr_start (xine_t *xine); - - -#endif /* XINELIBOUTPUT_ADJUSTABLE_SCR_H_ */ diff --git a/xine/demux_xvdr.c b/xine/demux_xvdr.c deleted file mode 100644 index e68dfa5c..00000000 --- a/xine/demux_xvdr.c +++ /dev/null @@ -1,1234 +0,0 @@ -/* - * Copyright (C) 2000-2006 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 xineliboutput (xvdr) - */ - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/demux.h> - -#include "../xine_input_vdr_mrl.h" -#include "../tools/mpeg.h" -#include "../tools/h264.h" -#include "../tools/pes.h" -#include "../tools/ts.h" - -#include "ts2es.h" -#include "demux_xvdr_tsdata.h" - -/* - * features - */ - -#define VDR_SUBTITLES -#define TEST_DVB_SPU - -/* - * logging - */ - -static const char log_module_demux_xvdr[] = "[demux_vdr] "; -#define LOG_MODULENAME log_module_demux_xvdr -#define SysLogLevel iSysLogLevel - -#include "../logdefs.h" - -#define LOGSPU(x...) - -/* - * constants - */ - -#define DISC_TRESHOLD 90000 -#define WRAP_THRESHOLD 120000 -#define PTS_AUDIO 0 -#define PTS_VIDEO 1 - - -/* redefine abs as macro to handle 64-bit diffs. - i guess llabs may not be available everywhere */ -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - -typedef struct demux_xvdr_s { - demux_plugin_t demux_plugin; - - xine_stream_t *stream; - fifo_buffer_t *audio_fifo; - fifo_buffer_t *video_fifo; - - input_plugin_t *input; - - ts_data_t *ts_data; /* MPEG-TS stuff */ - - int64_t last_pts[2]; - int64_t last_vpts; - int status; - uint32_t video_type; - uint32_t audio_type; - uint32_t subtitle_type; - - /* current buf_element */ - int64_t pts; - int64_t dts; - uint32_t packet_len; - uint8_t stream_id; - - uint8_t send_newpts : 1; - uint8_t buf_flag_seek : 1; - uint8_t ffmpeg_mpeg2_decoder : 1; - uint8_t coreavc_h264_decoder : 1; - uint8_t bih_posted : 1; -} demux_xvdr_t ; - -typedef struct { - - demux_class_t demux_class; - - /* class-wide, global variables here */ - - xine_t *xine; - config_values_t *config; -} demux_xvdr_class_t; - - -static const char * get_decoder_name(xine_t *xine, int video_type) -{ - int streamtype = (video_type >> 16) & 0xFF; - plugin_node_t *node = xine->plugin_catalog->video_decoder_map[streamtype][0]; - if (node) { - plugin_info_t *info = node->info; - if (info) - return info->id; - } - return ""; -} - -static void detect_video_decoders(demux_xvdr_t *this) -{ - if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_MPEG), "ffmpegvideo")) - this->ffmpeg_mpeg2_decoder = 1; - LOGMSG("Using decoder \"%s\" for mpeg2 video", - this->ffmpeg_mpeg2_decoder ? "FFmpeg" : "libmpeg2"); - - if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_H264), "dshowserver")) - this->coreavc_h264_decoder = 1; - LOGMSG("Using decoder \"%s\" for H.264 video", - this->coreavc_h264_decoder ? "dshowserver (CoreAVC)" : "FFmpeg"); -} - -static void demux_xvdr_parse_ts(demux_xvdr_t *this, buf_element_t *buf); -static void demux_xvdr_parse_pes(demux_xvdr_t *this, buf_element_t *buf); - -static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); - -static void pts_wrap_workaround(demux_xvdr_t *this, buf_element_t *buf, int video) -{ -#ifdef LOG_PES_AV_DIFF - static int64_t vpts = 0, apts = 0; - if (video) vpts = buf->pts; - else apts = buf->pts; - if (vpts > 0 && apts > 0) - LOGMSG("pts diff [%d] %d", video, (int)(vpts - apts)); -#endif - - /* PTS wrap workaround */ - if (buf->pts >= 0) { - if (video) - this->last_vpts = buf->pts; - else if (buf->pts > INT64_C( 0x40400000 ) && - this->last_vpts < INT64_C( 0x40000000 ) && - this->last_vpts > INT64_C( 0 )) { - LOGMSG("VIDEO pts wrap before AUDIO, ignoring audio pts %" PRId64, buf->pts); - buf->pts = INT64_C(0); - } - } -} - -static void check_newpts(demux_xvdr_t *this, buf_element_t *buf, int video ) -{ - pts_wrap_workaround(this, buf, video); - - if (buf->pts) { - int64_t diff = buf->pts - this->last_pts[video]; - - if (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD)) { - - if (this->buf_flag_seek) { - _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK); - this->buf_flag_seek = 0; - } else { - _x_demux_control_newpts(this->stream, buf->pts, 0); - } - this->send_newpts = 0; - - this->last_pts[1-video] = 0; - } - - this->last_pts[video] = buf->pts; - } -} - -static void put_control_buf(fifo_buffer_t *buffer, fifo_buffer_t *pool, int cmd) -{ - buf_element_t *buf = pool->buffer_pool_try_alloc(pool); - if(buf) { - buf->type = cmd; - buffer->put(buffer, buf); - } -} - -/* - * post_sequence_end() - * - * Add MPEG2 or H.264 sequence end code to fifo buffer - */ -static void post_sequence_end(fifo_buffer_t *fifo, uint32_t video_type) -{ - buf_element_t *buf = fifo->buffer_pool_try_alloc(fifo); - if (buf) { - buf->type = video_type; - buf->size = 4; - buf->decoder_flags = BUF_FLAG_FRAME_END; - buf->content[0] = 0x00; - buf->content[1] = 0x00; - buf->content[2] = 0x01; - buf->content[3] = (video_type == BUF_VIDEO_H264) ? NAL_END_SEQ : 0xB7; - fifo->put(fifo, buf); - } -} - -/* - * post_frame_end() - * - * Signal end of video frame to decoder. - * - * This function is used with: - * - FFmpeg mpeg2 decoder - * - FFmpeg and CoreAVC H.264 decoders - * - NOT with libmpeg2 mpeg decoder - */ -static void post_frame_end(demux_xvdr_t *this, buf_element_t *vid_buf) -{ - buf_element_t *cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo) ?: - this->audio_fifo->buffer_pool_try_alloc (this->audio_fifo); - - if (!cbuf) { - LOGMSG("post_frame_end(): buffer_pool_try_alloc() failed, retrying"); - xine_usec_sleep (10*1000); - cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo); - if (!cbuf) { - LOGERR("post_frame_end(): get_buf_element() failed !"); - return; - } - } - - cbuf->type = this->video_type; - cbuf->decoder_flags = BUF_FLAG_FRAME_END; - - if (!this->bih_posted) { - video_size_t size = {0}; - if (pes_get_video_size(vid_buf->content, vid_buf->size, &size, this->video_type == BUF_VIDEO_H264)) { - - /* reset decoder buffer */ - cbuf->decoder_flags |= BUF_FLAG_FRAME_START; - - /* Fill xine_bmiheader for CoreAVC / H.264 */ - - if (this->video_type == BUF_VIDEO_H264 && this->coreavc_h264_decoder) { - xine_bmiheader *bmi = (xine_bmiheader*) cbuf->content; - - cbuf->decoder_flags |= BUF_FLAG_HEADER; - cbuf->decoder_flags |= BUF_FLAG_STDHEADER; /* CoreAVC: buffer contains bmiheader */ - cbuf->size = sizeof(xine_bmiheader); - - memset (bmi, 0, sizeof(xine_bmiheader)); - - bmi->biSize = sizeof(xine_bmiheader); - bmi->biWidth = size.width; - bmi->biHeight = size.height; - - bmi->biPlanes = 1; - bmi->biBitCount = 24; - bmi->biCompression = 0x34363248; - bmi->biSizeImage = 0; - bmi->biXPelsPerMeter = size.pixel_aspect.num; - bmi->biYPelsPerMeter = size.pixel_aspect.den; - bmi->biClrUsed = 0; - bmi->biClrImportant = 0; - } - - /* Set aspect ratio for ffmpeg mpeg2 / CoreAVC H.264 decoder - * (not for FFmpeg H.264 or libmpeg2 mpeg2 decoders) - */ - - if (size.pixel_aspect.num && - (this->video_type != BUF_VIDEO_H264 || this->coreavc_h264_decoder)) { - cbuf->decoder_flags |= BUF_FLAG_HEADER; - cbuf->decoder_flags |= BUF_FLAG_ASPECT; - /* pixel ratio -> frame ratio */ - if (size.pixel_aspect.num > size.height) { - cbuf->decoder_info[1] = size.pixel_aspect.num / size.height; - cbuf->decoder_info[2] = size.pixel_aspect.den / size.width; - } else { - cbuf->decoder_info[1] = size.pixel_aspect.num * size.width; - cbuf->decoder_info[2] = size.pixel_aspect.den * size.height; - } - } - - LOGDBG("post_frame_end: video width %d, height %d, pixel aspect %d:%d", - size.width, size.height, size.pixel_aspect.num, size.pixel_aspect.den); - - this->bih_posted = 1; - } - } - - this->video_fifo->put (this->video_fifo, cbuf); -} - -static void track_audio_stream_change(demux_xvdr_t *this, buf_element_t *buf) -{ -#if !defined(BUF_CONTROL_RESET_TRACK_MAP) -# warning xine-lib is older than 1.1.2. Multiple audio streams are not supported. -#else - if (this->audio_type != buf->type) { - LOGDBG("audio stream changed: %08x -> %08x", this->audio_type, buf->type); - this->audio_type = buf->type; - put_control_buf(this->audio_fifo, - this->audio_fifo, - BUF_CONTROL_RESET_TRACK_MAP); - } -#endif -} - -static void demux_xvdr_fwd_buf(demux_xvdr_t *this, buf_element_t *buf) -{ - /* demuxed video --> video_fifo */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) { - this->video_type = buf->type; - check_newpts (this, buf, PTS_VIDEO); - this->video_fifo->put (this->video_fifo, buf); - return; - } - - /* demuxed audio --> audio_fifo */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_AUDIO_BASE) { - if (this->audio_fifo) { - check_newpts (this, buf, PTS_AUDIO); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - } else { - buf->free_buffer (buf); - } - return; - } - - /* decoder flush --> video_fifo */ - if (buf->type == BUF_CONTROL_FLUSH_DECODER) { - /* append sequence end code */ - post_sequence_end (this->video_fifo, this->video_type); - this->video_fifo->put (this->video_fifo, buf); - return; - } - - /* control buffer --> both fifos */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) { - if (this->audio_fifo) { - /* duplicate goes to audio fifo */ - buf_element_t *cbuf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - cbuf->type = buf->type; - cbuf->decoder_flags = buf->decoder_flags; - memcpy (cbuf->decoder_info, buf->decoder_info, sizeof(cbuf->decoder_info)); - memcpy (cbuf->decoder_info_ptr, buf->decoder_info_ptr, sizeof(cbuf->decoder_info_ptr)); - - this->audio_fifo->put (this->audio_fifo, cbuf); - } - this->video_fifo->put (this->video_fifo, buf); - return; - } - - LOGMSG("Unhandled buffer type %08x", buf->type); - buf->free_buffer (buf); -} - -static void demux_xvdr_parse_pack (demux_xvdr_t *this) -{ - buf_element_t *buf = NULL; - uint8_t *p; - - buf = this->input->read_block (this->input, this->video_fifo, 8128); - - if (!buf) { - if (errno == EINTR) { - /* very verbose logging ? */ - if (iSysLogLevel >= SYSLOGLEVEL_VERBOSE) - LOGDBG("input->read_block() was interrupted"); - } else if (errno != EAGAIN) { - LOGDBG("DEMUX_FINISHED (input returns NULL with error)"); - this->status = DEMUX_FINISHED; - ts_data_dispose(&this->ts_data); - } - return; - } - - /* If this is not a block for the demuxer, pass it - * straight through. */ - if (buf->type != BUF_DEMUX_BLOCK) { - ts_data_flush (this->ts_data); - demux_xvdr_fwd_buf (this, buf); - return; - } - - p = buf->content; /* len = this->blocksize; */ - buf->decoder_flags = 0; - - if (DATA_IS_TS(p)) { - demux_xvdr_parse_ts (this, buf); - return; - } - if (DATA_IS_PES(p)) { - demux_xvdr_parse_pes (this, buf); - return; - } - - LOGMSG("Header %02x %02x %02x (should be 0x000001 or 0x47)", p[0], p[1], p[2]); - buf->free_buffer (buf); - return; -} - -static void demux_xvdr_parse_pes (demux_xvdr_t *this, buf_element_t *buf) -{ - uint8_t *p = buf->content; - int32_t result; - - this->stream_id = p[3]; - - if (IS_VIDEO_PACKET(p)) { - result = parse_video_stream(this, p, buf); - } else if (IS_MPEG_AUDIO_PACKET(p)) { - result = parse_audio_stream(this, p, buf); - } else if (IS_PADDING_PACKET(p)) { - result = parse_padding_stream(this, p, buf); - } else if (IS_PS1_PACKET(p)) { - result = parse_private_stream_1(this, p, buf); - } else { - LOGMSG("Unrecognised PES stream 0x%02x", this->stream_id); - buf->free_buffer (buf); - return; - } - - if (result < 0) { - return; - } - - LOGMSG("error! freeing buffer."); - buf->free_buffer (buf); -} - -/* - * demux_xvdr_parse_ts() - * - * MPEG-TS demuxing - */ -static void demux_xvdr_parse_ts (demux_xvdr_t *this, buf_element_t *buf) -{ - if (!this->ts_data) - this->ts_data = calloc(1, sizeof(ts_data_t)); - - ts_data_t *ts_data = this->ts_data; - fifo_buffer_t *src_fifo = buf->source; - - while (buf->size >= TS_SIZE) { - - unsigned int ts_pid = ts_PID(buf->content); - - /* parse PAT */ - if (ts_pid == 0) { - pat_data_t pat; - - ts_data_flush(ts_data); - - if (ts_parse_pat(&pat, buf->content)) { - ts_data->pmt_pid = pat.pmt_pid[0]; - ts_data->program_number = pat.program_number[0]; - if (iSysLogLevel >= SYSLOGLEVEL_VERBOSE) - LOGDBG("Got PAT, PMT pid = %d, program = %d", ts_data->pmt_pid, ts_data->program_number); - } - } - - /* parse PMT */ - else if (ts_pid == ts_data->pmt_pid) { - - ts_data_flush(ts_data); - - if (ts_parse_pmt(&ts_data->pmt, ts_data->program_number, buf->content)) { - - /* PMT changed, reset ts->es converters */ - LOGMSG("PMT changed"); - ts_data_ts2es_init(&ts_data, this->stream->video_fifo, this->stream->audio_fifo); - - this->video_type = (ts_data->pmt.video_type == ISO_14496_PART10_VIDEO) ? - BUF_VIDEO_H264 : BUF_VIDEO_MPEG; - - /* Inform UI of channels changes */ - xine_event_t event; - event.type = XINE_EVENT_UI_CHANNELS_CHANGED; - event.data_length = 0; - xine_event_send(this->stream, &event); - } - } - - /* demux video */ - else if (ts_pid == ts_data->pmt.video_pid) { - if (ts_data->video) { - buf_element_t *vbuf = ts2es_put(ts_data->video, buf->content, src_fifo); - if (vbuf) { - this->pts = vbuf->pts; - check_newpts( this, vbuf, PTS_VIDEO ); - - this->stream->video_fifo->put(this->stream->video_fifo, vbuf); - } - } - } - - /* demux audio */ - else { - int i, done = 0; - for (i=0; i < ts_data->pmt.audio_tracks_count; i++) - if (ts_pid == ts_data->pmt.audio_tracks[i].pid) { - if (ts_data->audio[i]) { - buf_element_t *abuf = ts2es_put(ts_data->audio[i], buf->content, src_fifo); - if (abuf) { - this->pts = abuf->pts; - check_newpts( this, abuf, PTS_AUDIO ); - track_audio_stream_change (this, abuf); - - this->stream->audio_fifo->put(this->stream->audio_fifo, abuf); - } - } - done = 1; - break; - } -#if 0 - /* demux subtitles */ - if (!done) - for (i=0; i < ts_data->pmt.spu_tracks_count; i++) - if (ts_pid == ts_data->pmt.spu_tracks[i].pid) { - if (ts_data->spu[i]) { - buf_element_t *sbuf = ts2es_put(ts_data->spu[i], buf->content, NULL); - if (sbuf) - this->stream->video_fifo->put(this->stream->video_fifo, sbuf); - } - done = 1; - break; - } - - if (!done) - LOGMSG("Got unknown TS packet, pid = %d", ts_pid); -#endif - } - - buf->content += TS_SIZE; - buf->size -= TS_SIZE; - } - - buf->free_buffer(buf); -} - -static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - buf->free_buffer (buf); - return -1; -} - -/* FIXME: Extension data is not parsed, and is also not skipped. */ - -static int32_t parse_pes_for_pts(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int32_t header_len; - - this->packet_len = p[4] << 8 | p[5]; - - if ((p[6] & 0xC0) != 0x80 /* mpeg1 */) { - header_len = 6; - p += 6; /* packet_len -= 6; */ - - while ((p[0] & 0x80) == 0x80) { - p++; - header_len++; - this->packet_len--; - } - - if ((p[0] & 0xc0) == 0x40) { - /* STD_buffer_scale, STD_buffer_size */ - p += 2; - header_len += 2; - this->packet_len -= 2; - } - - this->pts = 0; - this->dts = 0; - - if ((p[0] & 0xf0) == 0x20) { - this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ; - this->pts |= p[ 1] << 22 ; - this->pts |= (p[ 2] & 0xFE) << 14 ; - this->pts |= p[ 3] << 7 ; - this->pts |= (p[ 4] & 0xFE) >> 1 ; - p += 5; - header_len+= 5; - this->packet_len -=5; - return header_len; - } else if ((p[0] & 0xf0) == 0x30) { - this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ; - this->pts |= p[ 1] << 22 ; - this->pts |= (p[ 2] & 0xFE) << 14 ; - this->pts |= p[ 3] << 7 ; - this->pts |= (p[ 4] & 0xFE) >> 1 ; - - this->dts = (int64_t)(p[ 5] & 0x0E) << 29 ; - this->dts |= p[ 6] << 22 ; - this->dts |= (p[ 7] & 0xFE) << 14 ; - this->dts |= p[ 8] << 7 ; - this->dts |= (p[ 9] & 0xFE) >> 1 ; - - p += 10; - header_len += 10; - this->packet_len -= 10; - return header_len; - } else { - p++; - header_len++; - this->packet_len--; - return header_len; - } - - } else { /* mpeg 2 */ - - - if ((p[6] & 0xC0) != 0x80) { - LOGMSG("warning: PES header reserved 10 bits not found"); - buf->free_buffer(buf); - return -1; - } - - - /* check PES scrambling_control */ - if ((p[6] & 0x30) != 0) { - LOGMSG("encrypted PES ?"); - buf->free_buffer(buf); - return -1; - } - - if (p[7] & 0x80) { /* pts avail */ - - this->pts = (int64_t)(p[ 9] & 0x0E) << 29 ; - this->pts |= p[10] << 22 ; - this->pts |= (p[11] & 0xFE) << 14 ; - this->pts |= p[12] << 7 ; - this->pts |= (p[13] & 0xFE) >> 1 ; - - } else - this->pts = 0; - - if (p[7] & 0x40) { /* dts avail */ - - this->dts = (int64_t)(p[14] & 0x0E) << 29 ; - this->dts |= p[15] << 22 ; - this->dts |= (p[16] & 0xFE) << 14 ; - this->dts |= p[17] << 7 ; - this->dts |= (p[18] & 0xFE) >> 1 ; - - } else - this->dts = 0; - - - header_len = p[8]; - - this->packet_len -= header_len + 3; - return header_len + 9; - } - return 0; -} - -#if defined(TEST_DVB_SPU) -/* - * parse_dvb_spu() - * - * DVB subtitle stream demuxing - */ -static int32_t parse_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf, int substream_header_len) -{ - uint spu_id = p[0] & 0x1f; - _x_select_spu_channel(this->stream, spu_id); - -# ifdef VDR_SUBTITLES - if (substream_header_len == 1) { - p--; - this->packet_len++; - } -# endif /* VDR_SUBTITLES */ - - /* Skip substream header */ - p += substream_header_len; - buf->content = p; - buf->size = this->packet_len - substream_header_len; - - /* Special buffer when payload packet changes */ - if (this->pts > 0) { - buf_element_t *cbuf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - int page_id = (*(p+4) << 8) | *(p+5); - - spu_dvb_descriptor_t *spu_descriptor = (spu_dvb_descriptor_t *) cbuf->content; - memset(spu_descriptor, 0, sizeof(spu_dvb_descriptor_t)); - spu_descriptor->comp_page_id = page_id; - - cbuf->type = BUF_SPU_DVB + spu_id; - cbuf->size = 0; - cbuf->decoder_flags = BUF_FLAG_SPECIAL; - cbuf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR; - cbuf->decoder_info[2] = sizeof(spu_dvb_descriptor_t); - cbuf->decoder_info_ptr[2] = spu_descriptor; - - this->video_fifo->put (this->video_fifo, cbuf); - } - - buf->type = BUF_SPU_DVB + spu_id; - buf->pts = this->pts; - buf->decoder_info[2] = this->pts > 0 ? 0xffff : 0; /* hack - size unknown here (?) */ - - this->video_fifo->put (this->video_fifo, buf); - - return -1; -} - -int detect_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - LOGSPU("%s%02x %02x %02x %02x %02x %02x %02x %02x", - this->pts>0?"* ":" ",p[0], p[1], p[2], p[3], - p[4], p[5], p[6], p[7]); - - /* If PES packet has PTS, it starts new subtitle (ES) packet. */ - if (this->pts > 0) { - /* Reset SPU type */ - this->subtitle_type = 0; - } - -# ifdef VDR_SUBTITLES - /* Compatibility mode for old subtitles plugin */ - if (this->subtitle_type != BUF_SPU_DVD) { - if ((buf->content[7] & 0x01) && (p[-3] & 0x81) == 0x01 && p[-2] == 0x81) { - LOGDBG("DVB SPU: Old vdr-subtitles compability mode"); - return parse_dvb_spu(this, p, buf, 1); - } - } -# endif /* VDR_SUBTITLES */ - - /* Start of subtitle packet. Guess substream type */ - if (this->pts > 0) { - if (p[4] == 0x20 && p[5] == 0x00 && (p[6] == 0x0f || p[4] == 0x0f)) { - this->subtitle_type = BUF_SPU_DVB; - LOGSPU(" -> DVB SPU"); - } else if (p[2] || (p[3] & 0xfe)) { - this->subtitle_type = BUF_SPU_DVD; - LOGSPU(" -> DVD SPU"); - } else { - this->subtitle_type = BUF_SPU_DVD; - LOGMSG(" -> DV? SPU -> DVD"); - } - } - - /* DVD SPU ? */ - if (this->subtitle_type == BUF_SPU_DVD) - return this->packet_len; - - /* DVB SPU */ - return parse_dvb_spu(this, p, buf, 4); -} - -#endif /* TEST_DVB_SPU */ - -static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int track, spu_id; - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - /* SPU */ - if ((p[0] & 0xE0) == 0x20) { - spu_id = (p[0] & 0x1f); - - if (this->pts <= 0 && !this->subtitle_type) { - /* need whole ES packet (after seek etc.) */ - buf->free_buffer(buf); - return -1; - } - -#ifdef TEST_DVB_SPU - if (detect_dvb_spu(this, p, buf) < 0) - return -1; -#endif /* TEST_DVB_SPU */ - this->subtitle_type = BUF_SPU_DVD; - - /* DVD SPU */ - buf->content = p+1; - buf->size = this->packet_len-1; - - buf->type = BUF_SPU_DVD + spu_id; - buf->decoder_flags |= BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; - buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; - buf->pts = this->pts; - - this->video_fifo->put (this->video_fifo, buf); - - return -1; - } - - if ((p[0]&0xF0) == 0x80) { - - track = p[0] & 0x0F; /* hack : ac3 track */ - - buf->decoder_info[1] = p[1]; /* Number of frame headers */ - buf->decoder_info[2] = p[2] << 8 | p[3]; /* First access unit pointer */ - - buf->content = p+4; - buf->size = this->packet_len-4; - if (track & 0x8) { - buf->type = BUF_AUDIO_DTS + (track & 0x07); /* DVDs only have 8 tracks */ - } else { - buf->type = BUF_AUDIO_A52 + track; - } - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - return -1; - } else { - buf->free_buffer(buf); - return -1; - } - - } else if ((p[0]&0xf0) == 0xa0) { - - int pcm_offset; - int number_of_frame_headers; - int first_access_unit_pointer; - int audio_frame_number; - int bits_per_sample; - int sample_rate; - int num_channels; - int dynamic_range; - - /* - * found in http://members.freemail.absa.co.za/ginggs/dvd/mpeg2_lpcm.txt - * appears to be correct. - */ - - track = p[0] & 0x0F; - number_of_frame_headers = p[1]; - /* unknown = p[2]; */ - first_access_unit_pointer = p[3]; - audio_frame_number = p[4]; - - /* - * 000 => mono - * 001 => stereo - * 010 => 3 channel - * ... - * 111 => 8 channel - */ - num_channels = (p[5] & 0x7) + 1; - sample_rate = p[5] & 0x10 ? 96000 : 48000; - switch ((p[5]>>6) & 3) { - case 3: /* illegal, use 16-bits? */ - default: - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "illegal lpcm sample format (%d), assume 16-bit samples\n", (p[5]>>6) & 3 ); - case 0: bits_per_sample = 16; break; - case 1: bits_per_sample = 20; break; - case 2: bits_per_sample = 24; break; - } - dynamic_range = p[6]; - - /* send lpcm config byte */ - buf->decoder_flags |= BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; - buf->decoder_info[2] = p[5]; - - pcm_offset = 7; - - buf->content = p+pcm_offset; - buf->size = this->packet_len-pcm_offset; - buf->type = BUF_AUDIO_LPCM_BE + track; - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - return -1; - } else { - buf->free_buffer(buf); - return -1; - } - } - - buf->free_buffer(buf); - return -1; -} - -/* - * detect_h264() - * - * Detect video codec (MPEG2 or H.264) - */ -static int detect_h264(uint8_t *data) -{ - /* H.264 detection */ - if (data[0] == 0 && data[1] == 0 && data[2] == 1) { - if (data[3] == NAL_AUD) { - LOGMSG("H.264 scanner: Possible H.264 NAL AUD"); - return BUF_VIDEO_H264; - } - if (data[3] == 0) { - LOGDBG("H.264 scanner: Possible MPEG2 start code PICTURE (0x00)"); - return BUF_VIDEO_MPEG; - } - if (data[3] >= 0x80) { - LOGDBG("H.264 scanner: Possible MPEG2 start code (0x%02x)", data[3]); - return BUF_VIDEO_MPEG; - } - LOGMSG("H.264 scanner: Unregonized header 00 00 01 %02x", data[3]); - } - - return 0; -} - -static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - if (this->video_type == 0) { - this->video_type = detect_h264(p); - } - - buf->type = this->video_type ?: BUF_VIDEO_MPEG; - buf->pts = this->pts; - buf->decoder_info[0] = this->pts - this->dts; - - /* MPEG2 */ - if (this->video_type == BUF_VIDEO_MPEG) { - /* Special handling for FFMPEG MPEG2 decoder */ - if (this->ffmpeg_mpeg2_decoder) { - uint8_t type = pes_get_picture_type(buf->content, buf->size); - if (type) { - /* signal FRAME_END to decoder */ - post_frame_end(this, buf); - /* for some reason ffmpeg mpeg2 decoder does not understand pts'es in B frames ? - * (B-frame pts's are smaller than in previous P-frame) - * Anyway, without this block of code B frames with pts are dropped. */ - if (type == B_FRAME) - buf->pts = 0; - } - } - } - - /* H.264 */ - else if (this->video_type == BUF_VIDEO_H264) { - /* Access Unit Delimiter */ - if (IS_NAL_AUD(p)) - post_frame_end (this, buf); - - /* Check for end of still image. - VDR ensures that H.264 still images end with an end of sequence NAL unit */ - if (buf->size > 4) { - uint8_t *end = buf->content + buf->size; - if (IS_NAL_END_SEQ(end-4)) { - LOGMSG("post_frame_h264: Still frame ? (frame ends with end of sequence NAL unit)"); - buf->decoder_flags |= BUF_FLAG_FRAME_END; - } - } - } - - buf->content = p; - buf->size = this->packet_len; - - check_newpts( this, buf, PTS_VIDEO ); - - this->video_fifo->put (this->video_fifo, buf); - - return -1; -} - -static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int track; - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - track = this->stream_id & 0x1f; - - buf->content = p; - buf->size = this->packet_len; - buf->type = BUF_AUDIO_MPEG + track; - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - } else { - buf->free_buffer(buf); - } - - return -1; -} - -/* - * interface - */ - -static int demux_xvdr_send_chunk (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - demux_xvdr_parse_pack(this); - - return this->status; -} - -static void demux_xvdr_dispose (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - LOGDBG("demux_xvdr_dispose()"); - - ts_data_dispose(&this->ts_data); - - free (this); -} - -static int demux_xvdr_get_status (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - if (this->status != DEMUX_OK) { - if (this->ts_data) { - LOGMSG("demux_xvdr_get_status(): status != DEMUX_OK. -> freeing ts_data"); - ts_data_dispose(&this->ts_data); - } - } - - return this->status; -} - -static void demux_xvdr_send_headers (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - this->video_fifo = this->stream->video_fifo; - this->audio_fifo = this->stream->audio_fifo; - - /* - * send start buffer - */ - - _x_demux_control_start(this->stream); - - this->status = DEMUX_OK; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, 5000000); -} - - -static int demux_xvdr_seek (demux_plugin_t *this_gen, - off_t start_pos, int start_time, int playing) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - /* - * now start demuxing - */ - this->send_newpts = 1; - this->video_type = 0; - this->audio_type = 0; - this->subtitle_type = 0; - this->bih_posted = 0; - ts_data_dispose(&this->ts_data); - - if (!playing) { - - this->buf_flag_seek = 0; - this->status = DEMUX_OK; - this->last_pts[0] = 0; - this->last_pts[1] = 0; - } else { - this->buf_flag_seek = 1; - this->last_vpts = INT64_C(-1); - _x_demux_flush_engine(this->stream); - } - - return this->status; -} - -/* - * demux class - */ - -static int demux_xvdr_get_stream_length (demux_plugin_t *this_gen) -{ - return 0; -} - -static uint32_t demux_xvdr_get_capabilities(demux_plugin_t *this_gen) -{ - return DEMUX_CAP_NOCAP; -} - -static int demux_xvdr_get_optional_data(demux_plugin_t *this_gen, - void *data, int data_type) -{ - return DEMUX_OPTIONAL_UNSUPPORTED; -} - -static demux_plugin_t *demux_xvdr_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, - input_plugin_t *input_gen) -{ - input_plugin_t *input = (input_plugin_t *) input_gen; - demux_xvdr_t *this; - const char *mrl = input->get_mrl(input); - - if (strncmp(mrl, MRL_ID ":/", MRL_ID_LEN + 2 ) && - strncmp(mrl, MRL_ID "+pipe://", MRL_ID_LEN + 8) && - strncmp(mrl, MRL_ID "+tcp://", MRL_ID_LEN + 7) && - strncmp(mrl, MRL_ID "+udp://", MRL_ID_LEN + 7) && - strncmp(mrl, MRL_ID "+rtp://", MRL_ID_LEN + 7)) - return NULL; - - this = calloc(1, sizeof(demux_xvdr_t)); - this->stream = stream; - this->input = input; - - this->demux_plugin.send_headers = demux_xvdr_send_headers; - this->demux_plugin.send_chunk = demux_xvdr_send_chunk; - this->demux_plugin.seek = demux_xvdr_seek; - this->demux_plugin.dispose = demux_xvdr_dispose; - this->demux_plugin.get_status = demux_xvdr_get_status; - this->demux_plugin.get_stream_length = demux_xvdr_get_stream_length; - this->demux_plugin.get_capabilities = demux_xvdr_get_capabilities; - this->demux_plugin.get_optional_data = demux_xvdr_get_optional_data; - this->demux_plugin.demux_class = class_gen; - - this->status = DEMUX_FINISHED; - - detect_video_decoders(this); - - return &this->demux_plugin; -} - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *demux_xvdr_get_description (demux_class_t *this_gen) -{ - return MRL_ID " demux plugin"; -} - -static const char *demux_xvdr_get_identifier (demux_class_t *this_gen) -{ - return MRL_ID; -} - -static const char *demux_xvdr_get_extensions (demux_class_t *this_gen) -{ - return NULL; -} - -static const char *demux_xvdr_get_mimetypes (demux_class_t *this_gen) -{ - return NULL; -} - -static void demux_xvdr_class_dispose (demux_class_t *this_gen) -{ - demux_xvdr_class_t *this = (demux_xvdr_class_t *) this_gen; - - free (this); -} -#endif - -void *demux_xvdr_init_class (xine_t *xine, void *data) -{ - demux_xvdr_class_t *this; - - this = calloc(1, sizeof(demux_xvdr_class_t)); - this->config = xine->config; - this->xine = xine; - - this->demux_class.open_plugin = demux_xvdr_open_plugin; -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 - this->demux_class.get_description = demux_xvdr_get_description; - this->demux_class.get_identifier = demux_xvdr_get_identifier; - this->demux_class.get_mimetypes = demux_xvdr_get_mimetypes; - this->demux_class.get_extensions = demux_xvdr_get_extensions; - this->demux_class.dispose = demux_xvdr_class_dispose; -#else - this->demux_class.description = N_("XVDR demux plugin"); - this->demux_class.identifier = MRL_ID; - this->demux_class.mimetypes = NULL; - this->demux_class.extensions = - MRL_ID":/ " - MRL_ID"+pipe:/ " - MRL_ID"+tcp:/ " - MRL_ID"+udp:/ " - MRL_ID"+rtp:/ " - MRL_ID"+slave:/"; - this->demux_class.dispose = default_demux_class_dispose; -#endif - - return this; -} - - diff --git a/xine/demux_xvdr_tsdata.c b/xine/demux_xvdr_tsdata.c deleted file mode 100644 index 38904a97..00000000 --- a/xine/demux_xvdr_tsdata.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * demux_xvdr_tsdata.h: data for MPEG-TS demuxer - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: demux_xvdr_tsdata.c,v 1.1 2009-02-24 19:50:42 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/buffer.h> - -#define LOG_MODULENAME "[demux_vdr] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - -#include "../tools/ts.h" -#include "ts2es.h" - -#include "demux_xvdr_tsdata.h" - -static void ts_data_ts2es_reset(ts_data_t *ts_data) -{ - int i; - - ts2es_dispose(ts_data->video); - ts_data->video = NULL; - - for (i = 0; ts_data->audio[i]; i++) { - ts2es_dispose(ts_data->audio[i]); - ts_data->audio[i] = NULL; - } - - for (i = 0; ts_data->spu[i]; i++) { - ts2es_dispose(ts_data->spu[i]); - ts_data->spu[i] = NULL; - } -} - -void ts_data_ts2es_init(ts_data_t **ts_data, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo) -{ - if (*ts_data) - ts_data_ts2es_reset(*ts_data); - else - *ts_data = calloc (1, sizeof(ts_data_t)); - - ts_data_t *this = *ts_data; - int i; - - if (video_fifo) { - if (this->pmt.video_pid != INVALID_PID) - this->video = ts2es_init(video_fifo, this->pmt.video_type, 0); - - for (i=0; i < this->pmt.spu_tracks_count; i++) - this->spu[i] = ts2es_init(video_fifo, STREAM_DVBSUB, i); - } - - if (audio_fifo) { - for (i=0; i < this->pmt.audio_tracks_count; i++) - this->audio[i] = ts2es_init(audio_fifo, this->pmt.audio_tracks[i].type, i); - } -} - -void ts_data_flush(ts_data_t *ts_data) -{ - if (ts_data) { - int i; - - if (ts_data->video) - ts2es_flush(ts_data->video); - - for (i = 0; ts_data->audio[i]; i++) - ts2es_flush(ts_data->audio[i]); - - for (i = 0; ts_data->spu[i]; i++) - ts2es_flush(ts_data->spu[i]); - } -} - -void ts_data_dispose(ts_data_t **ts_data) -{ - if (*ts_data) { - - ts_data_ts2es_reset(*ts_data); - - free(*ts_data); - *ts_data = NULL; - } -} diff --git a/xine/demux_xvdr_tsdata.h b/xine/demux_xvdr_tsdata.h deleted file mode 100644 index 96a1b893..00000000 --- a/xine/demux_xvdr_tsdata.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * demux_xvdr_tsdata.h: data for MPEG-TS demuxer - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: demux_xvdr_tsdata.h,v 1.1 2009-02-24 19:50:42 phintuka Exp $ - * - */ - -#ifndef _DEMUX_XVDR_TSDATA_H_ -#define _DEMUX_XVDR_TSDATA_H_ - -struct ts2es_s; - -struct ts_data_s { - uint16_t pmt_pid; - uint16_t program_number; - - pmt_data_t pmt; - - struct ts2es_s *video; - struct ts2es_s *audio[TS_MAX_AUDIO_TRACKS]; - struct ts2es_s *spu[TS_MAX_SPU_TRACKS]; -}; - -typedef struct ts_data_s ts_data_t; - -void ts_data_ts2es_init (ts_data_t **ts_data, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo); -void ts_data_flush (ts_data_t *ts_data); -void ts_data_dispose (ts_data_t **ts_data); - - -#endif /* _DEMUX_XVDR_TSDATA_H_ */ diff --git a/xine/osd_manager.c b/xine/osd_manager.c deleted file mode 100644 index a7d0d6b4..00000000 --- a/xine/osd_manager.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * osd_manager.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd_manager.c,v 1.13 2009-06-02 14:17:05 phintuka Exp $ - * - */ - -#include <stdlib.h> -#include <pthread.h> - -#define XINE_ENGINE_INTERNAL -#include <xine/xine_internal.h> -#include <xine/video_out.h> - -#include "../xine_osd_command.h" -#include "../xine_input_vdr.h" - -#include "../tools/rle.h" - -#include "vo_props.h" -#include "osd_manager.h" - -/*#define LOGOSD(x...) LOGMSG(x)*/ -#define LOGOSD(x...) - -static const char log_module_input_osd[] = "[input_osd] "; -#define LOG_MODULENAME log_module_input_osd -#define SysLogLevel iSysLogLevel - -#include "../logdefs.h" - - -typedef struct { - int handle; /* xine-lib overlay handle */ - osd_command_t cmd; /* Full OSD data: last OSD_Set_RLE event */ - - uint16_t extent_width; /* output size this OSD was designed for */ - uint16_t extent_height; - - int64_t last_changed_vpts; -} osd_data_t; - -typedef struct osd_manager_impl_s { - osd_manager_t mgr; - - pthread_mutex_t lock; - uint8_t ticket_acquired; - xine_stream_t *stream; - - uint16_t video_width; - uint16_t video_height; - uint8_t vo_scaling; - - osd_data_t osd[MAX_OSD_OBJECT]; - -} osd_manager_impl_t; - -/************************************* Tools ************************************/ - -/* - * acquire_ticket() - */ -static void acquire_ticket(osd_manager_impl_t *this) -{ - if (!this->ticket_acquired) { - this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 1); - this->ticket_acquired = 1; - } -} - -static void release_ticket(osd_manager_impl_t *this) -{ - if (this->ticket_acquired) { - this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 1); - this->ticket_acquired = 0; - } -} - -/* - * get_overlay_manager() - */ -video_overlay_manager_t *get_ovl_manager(osd_manager_impl_t *this) -{ - /* Get overlay manager. We need ticket ... */ - acquire_ticket(this); - video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager(this->stream->video_out); - if (!ovl_manager) { - LOGMSG("Stream has no overlay manager !"); - return NULL; - } - return ovl_manager; -} - -/* - * palette_argb_to_ayuv() - */ - -#define saturate(x,min,max) ( (x)<(min) ? (min) : (x)>(max) ? (max) : (x)) - -static void palette_argb_to_ayuv(xine_clut_t *clut, int colors) -{ - if (clut && colors>0) { - int c; - for (c=0; c<colors; c++) { - int R = clut[c].r; - int G = clut[c].g; - int B = clut[c].b; - int Y = (( + 66*R + 129*G + 25*B + 0x80) >> 8) + 16; - int CR = (( + 112*R - 94*G - 18*B + 0x80) >> 8) + 128; - int CB = (( - 38*R - 74*G + 112*B + 0x80) >> 8) + 128; - clut[c].y = saturate( Y, 16, 235); - clut[c].cb = saturate(CB, 16, 240); - clut[c].cr = saturate(CR, 16, 240); - } - } -} - -/* - * clear_osdcmd() - * - * - free allocated memory from osd_command_t - */ -static void clear_osdcmd(osd_command_t *cmd) -{ - free(cmd->data); - cmd->data = NULL; - free(cmd->palette); - cmd->palette = NULL; -} - -/* - * osdcmd_to_overlay() - * - * - fill xine-lib vo_overlay_t from osd_command_t - */ -static void osdcmd_to_overlay(vo_overlay_t *ovl, osd_command_t *cmd) -{ - int i; - - ovl->rle = (rle_elem_t*)cmd->data; - ovl->data_size = cmd->datalen; - ovl->num_rle = cmd->datalen / 4; - - ovl->x = cmd->x; - ovl->y = cmd->y; - ovl->width = cmd->w; - ovl->height = cmd->h; - - /* palette */ - for (i=0; i<cmd->colors; i++) { - ovl->color[i] = (*(uint32_t*)(cmd->palette + i)) & 0x00ffffff; - ovl->trans[i] = (cmd->palette[i].alpha + 0x7)/0xf; - } - ovl->rgb_clut = cmd->flags & OSDFLAG_YUV_CLUT ? 0 : 1; - - ovl->unscaled = cmd->flags & OSDFLAG_UNSCALED ? 1 : 0; - - ovl->hili_top = ovl->hili_bottom = ovl->hili_left = ovl->hili_right = -1; -} - -/* - * osdcmd_scale() - * - * Scale OSD_Set_RLE data - * - modified fields: x, y, w, h, (RLE) data and datalen - * - old RLE data is stored to osd_data_t *osd - */ -static void osdcmd_scale(osd_manager_impl_t *this, osd_command_t *cmd, - osd_data_t *osd, int output_width, int output_height) -{ - LOGOSD("Size out of margins, rescaling rle image"); - - /* new position and size */ - int new_x = cmd->x * this->video_width / osd->extent_width; - int new_y = cmd->y * this->video_height / osd->extent_height; - int x2 = cmd->x + cmd->w + 1; - int y2 = cmd->y + cmd->h + 1; - x2 = ((x2+1) * this->video_width - 1) / osd->extent_width; - y2 = ((y2+1) * this->video_height - 1) / osd->extent_height; - int new_w = x2 - new_x - 1; - int new_h = y2 - new_y - 1; - - /* store original RLE data */ - osd->cmd.data = cmd->data; - osd->cmd.datalen = cmd->datalen; - - /* scale */ - int rle_elems = cmd->datalen / sizeof(xine_rle_elem_t); - cmd->data = rle_scale_nearest(cmd->data, &rle_elems, cmd->w, cmd->h, - new_w, new_h); - cmd->datalen = rle_elems * sizeof(xine_rle_elem_t); - - cmd->x = new_x; - cmd->y = new_y; - cmd->w = new_w; - cmd->h = new_h; -} - -/* - * osd_exec_vpts() - * - * - calculate execution time (vpts) for OSD update - */ -static int64_t osd_exec_vpts(osd_manager_impl_t *this, osd_command_t *cmd) -{ - int64_t vpts = 0; /* now */ - - /* calculate exec time */ - if (cmd->pts || cmd->delay_ms) { - int64_t now = xine_get_current_vpts(this->stream); - - if (cmd->pts) - vpts = cmd->pts + this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); - else - vpts = this->osd[cmd->wnd].last_changed_vpts + cmd->delay_ms*90; - - /* execution time must be in future */ - if (vpts < now) - vpts = 0; - - /* limit delay to 5 seconds */ - if (vpts > now + 5*90000) - vpts = vpts + 5*90000; - - LOGOSD("OSD Command %d scheduled to +%dms", cmd->cmd, (int)(vpts>now ? vpts-now : 0)/90); - } - - return vpts; -} - -/***************************** OSD command handlers *****************************/ - -/* - * exec_osd_size() - * - * - set the assumed full OSD size - */ -static int exec_osd_size(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - osd->extent_width = cmd->w; - osd->extent_height = cmd->h; - - acquire_ticket(this); - - xine_video_port_t *video_out = this->stream->video_out; - this->vo_scaling = 0; - if (video_out->get_capabilities(video_out) & VO_CAP_OSDSCALING) { - this->vo_scaling = 1; - } - - return CONTROL_OK; -} - -/* - * exec_osd_nop() - * - * - update last changed time of an OSD window - */ -static int exec_osd_nop(osd_manager_impl_t *this, osd_command_t *cmd) -{ - this->osd[cmd->wnd].last_changed_vpts = xine_get_current_vpts(this->stream); - return CONTROL_OK; -} - -/* - * exec_osd_flush() - * - * - commit all pending OSD events immediately - */ -static int exec_osd_flush(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - ovl_manager->flush_events(ovl_manager); - - return CONTROL_OK; -} - -/* - * exec_osd_close() - * - */ -static int exec_osd_close(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - osd_data_t *osd = &this->osd[cmd->wnd]; - int handle = osd->handle; - - if (cmd->flags & OSDFLAG_REFRESH) { - LOGDBG("Ignoring OSD_Close(OSDFLAG_REFRESH)"); - return CONTROL_OK; - } - - if (handle < 0) { - LOGMSG("OSD_Close(%d): non-existing OSD !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - video_overlay_event_t ov_event = {0}; - ov_event.event_type = OVERLAY_EVENT_FREE_HANDLE; - ov_event.vpts = osd_exec_vpts(this, cmd); - ov_event.object.handle = handle; - - while (ovl_manager->add_event(ovl_manager, (void *)&ov_event) < 0) { - LOGMSG("OSD_Close(%d): overlay manager queue full !", cmd->wnd); - ovl_manager->flush_events(ovl_manager); - } - - clear_osdcmd(&osd->cmd); - osd->handle = -1; - osd->extent_width = 720; - osd->extent_height = 576; - osd->last_changed_vpts = 0; - - return CONTROL_OK; -} - -/* - * exec_osd_set_rle() - * - */ -static int exec_osd_set_rle(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - video_overlay_event_t ov_event = {0}; - vo_overlay_t ov_overlay = {0}; - osd_data_t *osd = &this->osd[cmd->wnd]; - int use_unscaled = 0; - int rle_scaled = 0; - int unscaled_supported = 1; - int handle = osd->handle; - - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - this->stream->video_out->enable_ovl(this->stream->video_out, 1); - - /* get / allocate OSD handle */ - if (handle < 0) { - handle = ovl_manager->get_handle(ovl_manager,0); - osd->handle = handle; - osd->extent_width = osd->extent_width ?: 720; - osd->extent_height = osd->extent_height ?: 576; - osd->last_changed_vpts = 0; - } - - /* fill SHOW event */ - ov_event.event_type = OVERLAY_EVENT_SHOW; - ov_event.vpts = osd_exec_vpts(this, cmd); - ov_event.object.handle = handle; - ov_event.object.overlay = &ov_overlay; - ov_event.object.object_type = 1; /* menu */ - - /* check for unscaled OSD capability and request */ - xine_video_port_t *video_out = this->stream->video_out; - if (! (video_out->get_capabilities(video_out) & VO_CAP_UNSCALED_OVERLAY)) - unscaled_supported = 0; - else if (cmd->flags & OSDFLAG_UNSCALED) - use_unscaled = 1; - - /* store osd for later rescaling (done if video size changes) */ - - clear_osdcmd(&osd->cmd); - - memcpy(&osd->cmd, cmd, sizeof(osd_command_t)); - osd->cmd.data = NULL; - if (cmd->palette) { - /* RGB -> YUV */ - if(!(cmd->flags & OSDFLAG_YUV_CLUT)) - palette_argb_to_ayuv(cmd->palette, cmd->colors); - cmd->flags |= OSDFLAG_YUV_CLUT; - - osd->cmd.palette = malloc(sizeof(xine_clut_t)*cmd->colors); - memcpy(osd->cmd.palette, cmd->palette, 4*cmd->colors); - osd->cmd.flags |= OSDFLAG_YUV_CLUT; - } - - /* request OSD scaling from video_out layer */ - this->vo_scaling = 0; - if (video_out->get_capabilities(video_out) & VO_CAP_OSDSCALING) { - video_out->set_property(video_out, VO_PROP_OSD_SCALING, cmd->scaling ? 1 : 0); - this->vo_scaling = 1; - } - - /* if video size differs from expected (VDR osd is designed for 720x576), - scale osd to video size or use unscaled (display resolution) - blending */ - - /* scale OSD ? */ - if (!this->vo_scaling && !use_unscaled) { - int w_diff = (this->video_width < ((osd->extent_width *242) >> 8) /* 95% */) ? -1 : - (this->video_width > ((osd->extent_width *280) >> 8) /* 110% */) ? 1 : 0; - int h_diff = (this->video_height < ((osd->extent_height*242) >> 8) /* 95% */) ? -1 : - (this->video_height > ((osd->extent_height*280) >> 8) /* 110% */) ? 1 : 0; - - if (w_diff || h_diff) { - - /* unscaled OSD instead of downscaling ? */ - if (w_diff < 0 || h_diff < 0) - if (cmd->flags & OSDFLAG_UNSCALED_LOWRES) - if (0 < (use_unscaled = unscaled_supported)) - LOGOSD("Size out of margins, using unscaled overlay"); - - if (!use_unscaled && cmd->scaling > 0) { - osdcmd_scale(this, cmd, osd, this->video_width, this->video_height); - rle_scaled = 1; - } - } - } - - /* Scale unscaled OSD ? */ - if (!this->vo_scaling && use_unscaled && cmd->scaling > 0) { - int win_width = video_out->get_property(video_out, VO_PROP_WINDOW_WIDTH); - int win_height = video_out->get_property(video_out, VO_PROP_WINDOW_HEIGHT); - - if (win_width >= 360 && win_height >= 288) { - if (win_width != osd->extent_width || win_height != osd->extent_height) { - osdcmd_scale(this, cmd, osd, win_width, win_height); - rle_scaled = 1; - } - } - } - - /* fill ov_overlay */ - osdcmd_to_overlay(&ov_overlay, cmd); - ov_overlay.unscaled = use_unscaled; - - /* tag this overlay */ - ov_overlay.hili_rgb_clut = VDR_OSD_MAGIC; - - /* fill extra data */ - const vdr_osd_extradata_t extra_data = { - extent_width: osd->extent_width, - extent_height: osd->extent_height, - layer: cmd->layer, - scaling: cmd->scaling - }; - memcpy(ov_overlay.hili_color, &extra_data, sizeof(extra_data)); - -#ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - if (cmd->scaling && !rle_scaled) { - ov_overlay.extent_width = osd->extent_width; - ov_overlay.extent_height = osd->extent_height; - } -#endif - - /* if no scaling was required, we may still need to re-center OSD */ - if (!this->vo_scaling && !rle_scaled) { - if (this->video_width != osd->extent_width) - ov_overlay.x += (this->video_width - osd->extent_width)/2; - if (this->video_height != osd->extent_height) - ov_overlay.y += (this->video_height - osd->extent_height)/2; - } - - /* store rle for later scaling (done if video size changes) */ - if (!rle_scaled /* if scaled, we already have a copy (original data) */ ) { - osd->cmd.data = malloc(cmd->datalen); - memcpy(osd->cmd.data, cmd->data, cmd->datalen); - } - cmd->data = NULL; /* we 'consume' data (ownership goes for xine-lib osd manager) */ - - /* send event to overlay manager */ - while (ovl_manager->add_event(ovl_manager, (void *)&ov_event) < 0) { - LOGMSG("OSD_Set_RLE(%d): overlay manager queue full !", cmd->wnd); - ovl_manager->flush_events(ovl_manager); - } - - osd->last_changed_vpts = ov_event.vpts ?: xine_get_current_vpts(this->stream); - - return CONTROL_OK; -} - -/* - * exec_osd_set_palette() - * - * - replace palette of an already existing OSD - */ -static int exec_osd_set_palette(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - - if (!osd->cmd.data) { - LOGMSG("OSD_SetPalette(%d): old RLE data missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - if (!cmd->palette) { - LOGMSG("OSD_SetPalette(%d): new palette missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - /* use cached event to re-create Set_RLE command with modified palette */ - osd_command_t tmp; - /* steal the original command */ - memcpy(&tmp, &osd->cmd, sizeof(osd_command_t)); - memset(&osd->cmd, 0, sizeof(osd_command_t)); - - /* replace palette */ - tmp.cmd = OSD_Set_RLE; - free(tmp.palette); - tmp.palette = malloc(cmd->colors*sizeof(xine_rle_elem_t)); - memcpy(tmp.palette, cmd->palette, cmd->colors*sizeof(xine_rle_elem_t)); - tmp.colors = cmd->colors; - tmp.pts = cmd->pts; - tmp.delay_ms = cmd->delay_ms; - tmp.flags |= cmd->flags & OSDFLAG_YUV_CLUT; - - /* redraw */ - int r = exec_osd_set_rle(this, &tmp); - clear_osdcmd(&tmp); - return r; -} - -/* - * exec_osd_move() - * - * - move existing OSD to new position - */ -static int exec_osd_move(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - - if (!osd->cmd.data) { - LOGMSG("OSD_Move(%d): old RLE data missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - if (!osd->cmd.palette) { - LOGMSG("OSD_Move(%d): old palette missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - /* use cached event to re-create Set_RLE command with modified palette */ - osd_command_t tmp; - /* steal the original command */ - memcpy(&tmp, &osd->cmd, sizeof(osd_command_t)); - memset(&osd->cmd, 0, sizeof(osd_command_t)); - - /* replace position */ - tmp.cmd = OSD_Set_RLE; - tmp.x = cmd->x; - tmp.y = cmd->y; - tmp.pts = cmd->pts; - tmp.delay_ms = cmd->delay_ms; - - /* redraw */ - int r = exec_osd_set_rle(this, &tmp); - clear_osdcmd(&tmp); - return r; -} - -/* - * exec_osd_command_internal() - */ -static int exec_osd_command_internal(osd_manager_impl_t *this, struct osd_command_s *cmd) -{ - LOGOSD("exec_osd_command %d", cmd->cmd); - - switch (cmd->cmd) { - case OSD_Nop: return exec_osd_nop(this, cmd); - case OSD_Size: return exec_osd_size(this, cmd); - case OSD_SetPalette: return exec_osd_set_palette(this, cmd); - case OSD_Move: return exec_osd_move(this, cmd); - case OSD_Flush: return exec_osd_flush(this, cmd); - case OSD_Set_RLE: return exec_osd_set_rle(this, cmd); - case OSD_Close: return exec_osd_close(this, cmd); - case OSD_Set_YUV: - /* TODO */ - LOGMSG("OSD_Set_YUV not implemented !"); - return CONTROL_PARAM_ERROR; - } - - LOGMSG("Unknown OSD command %d", cmd->cmd); - return CONTROL_PARAM_ERROR; -} - -/****************************** Interface handlers ******************************/ - -/* - * exec_osd_command() - * - * - handler for VDR-based osd_command_t events - */ -static int exec_osd_command(osd_manager_t *this_gen, - struct osd_command_s *cmd, xine_stream_t *stream) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int result; - - if (!cmd || !stream) { - LOGMSG("exec_osd_command: Stream not initialized !"); - return CONTROL_DISCONNECTED; - } - if (cmd->wnd >= MAX_OSD_OBJECT) { - LOGMSG("exec_osd_command: OSD window handle %d out of range !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - if (pthread_mutex_lock(&this->lock)) { - LOGERR("exec_osd_command: mutex lock failed"); - return CONTROL_DISCONNECTED; - } - - this->stream = stream; - result = exec_osd_command_internal(this, cmd); - - release_ticket(this); - - pthread_mutex_unlock(&this->lock); - - return result; -} - -/* - * video_size_changed() - */ -static void video_size_changed(osd_manager_t *this_gen, xine_stream_t *stream, int width, int height) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int i; - - if (!stream) { - LOGMSG("video_size_changed: Stream not initialized !"); - return; - } - - if (width < 1 || height < 1) { - LOGMSG("video_size_changed: Invalid video size %dx%d", width, height); - return; - } - - if (pthread_mutex_lock(&this->lock)) { - LOGERR("video_size_changed: mutex lock failed"); - return; - } - - if (this->video_width == width && this->video_height == height) { - pthread_mutex_unlock(&this->lock); - return; - } - - LOGOSD("New video size (%dx%d->%dx%d)", this->video_width, this->video_height, width, height); - - this->stream = stream; - this->video_width = width; - this->video_height = height; - - /* just call exec_osd_command for all stored osd's. - scaling is done automatically if required. */ - if (!this->vo_scaling) - for (i = 0; i < MAX_OSD_OBJECT; i++) - if (this->osd[i].handle >= 0 && - this->osd[i].cmd.data && - this->osd[i].cmd.scaling > 0) { - osd_command_t tmp; - memcpy(&tmp, &this->osd[i].cmd, sizeof(osd_command_t)); - memset(&this->osd[i].cmd, 0, sizeof(osd_command_t)); - - exec_osd_command_internal(this, &tmp); - - clear_osdcmd(&tmp); - } - - release_ticket(this); - pthread_mutex_unlock(&this->lock); -} - -/* - * osd_manager_dispose() - */ -static void osd_manager_dispose(osd_manager_t *this_gen, xine_stream_t *stream) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int i; - - while (pthread_mutex_destroy(&this->lock) == EBUSY) { - LOGMSG("osd_manager_dispose: lock busy ..."); - pthread_mutex_lock(&this->lock); - pthread_mutex_unlock(&this->lock); - } - - /* close all */ - for (i=0; i<MAX_OSD_OBJECT; i++) { - if (this->osd[i].handle >= 0) { - osd_command_t cmd = { - .cmd = OSD_Close, - .wnd = i, - }; - LOGOSD("Closing osd %d", i); - exec_osd_close(this, &cmd); - } - } - - release_ticket(this); - - free(this); -} - -/* - * init_osd_manager() - * - * - exported - */ -osd_manager_t *init_osd_manager(void) -{ - osd_manager_impl_t *this = calloc(1, sizeof(osd_manager_impl_t)); - int i; - - this->mgr.command = exec_osd_command; - this->mgr.dispose = osd_manager_dispose; - this->mgr.video_size_changed = video_size_changed; - - pthread_mutex_init(&this->lock, NULL); - - this->video_width = 720; - this->video_height = 576; - - for (i = 0; i < MAX_OSD_OBJECT; i++) - this->osd[i].handle = -1; - - return &this->mgr; -} diff --git a/xine/osd_manager.h b/xine/osd_manager.h deleted file mode 100644 index d71336ed..00000000 --- a/xine/osd_manager.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * osd_manager.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd_manager.h,v 1.1 2008-12-06 16:17:18 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_OSD_MANAGER_H_ -#define XINELIBOUTPUT_OSD_MANAGER_H_ - -/* - * OSD manager executes OSD control messages from VDR. - * - cache OSD data - * - scale OSD when required - * - re-scale OSD when video size changes - * - generate xine overlay events - */ - -struct osd_command_s; - -typedef struct osd_manager_s osd_manager_t; - -struct osd_manager_s { - int (*command)(osd_manager_t *, struct osd_command_s *, xine_stream_t *); - void (*dispose)(osd_manager_t *, xine_stream_t *); - - void (*video_size_changed)(osd_manager_t *, xine_stream_t *, int width, int height); -}; - -osd_manager_t *init_osd_manager(void); - - -#endif /* XINELIBOUTPUT_OSD_MANAGER_H_ */ diff --git a/xine/post.c b/xine/post.c deleted file mode 100644 index 6c637634..00000000 --- a/xine/post.c +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright (C) 2003 by Dirk Meyer - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * The code is taken from xine-ui/src/xitk/post.c at changed to work with fbxine - * - * Modified for VDR xineliboutput plugin by Petri Hintukainen, 2006 - * - runtime re-configuration (load/unload, enable/disable) - * - support for multiple streams - * - support for mosaico post plugin (picture-in-picture) - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "post.h" - -#include <sys/types.h> -#include <sys/syscall.h> -#include <unistd.h> -#include <errno.h> -#include <syslog.h> - -#define LOG_MODULENAME "[xine-post] " -#include "../logdefs.h" - -#define fe_t post_plugins_t - -typedef struct { - xine_post_t *post; - xine_post_api_t *api; - xine_post_api_descr_t *descr; - xine_post_api_parameter_t *param; - char *param_data; - - int x; - int y; - - int readonly; - - char **properties_names; -} post_object_t; - - -static int __pplugin_retrieve_parameters(post_object_t *pobj) -{ - xine_post_in_t *input_api; - - if((input_api = (xine_post_in_t *) xine_post_input(pobj->post, - "parameters"))) { - xine_post_api_t *post_api; - xine_post_api_descr_t *api_descr; - xine_post_api_parameter_t *parm; - int pnum = 0; - - post_api = (xine_post_api_t *) input_api->data; - - api_descr = post_api->get_param_descr(); - - parm = api_descr->parameter; - pobj->param_data = malloc(api_descr->struct_size); - - while(parm->type != POST_PARAM_TYPE_LAST) { - - post_api->get_parameters(pobj->post, pobj->param_data); - - if(!pnum) - pobj->properties_names = (char **) calloc(2, sizeof(char *)); - else - pobj->properties_names = (char **) - realloc(pobj->properties_names, sizeof(char *) * (pnum + 2)); - - pobj->properties_names[pnum] = strdup(parm->name); - pobj->properties_names[pnum + 1] = NULL; - pnum++; - parm++; - } - - pobj->api = post_api; - pobj->descr = api_descr; - pobj->param = api_descr->parameter; - - return 1; - } - - return 0; -} - -static void _pplugin_update_parameter(post_object_t *pobj) -{ - pobj->api->set_parameters(pobj->post, pobj->param_data); - pobj->api->get_parameters(pobj->post, pobj->param_data); -} - -static void __pplugin_update_parameters(xine_post_t *post, char *args) -{ - char *p; - post_object_t pobj = { - .post = post, - }; - - if(__pplugin_retrieve_parameters(&pobj)) { - int i; - - if(pobj.properties_names && args && *args) { - char *param; - - while((param = xine_strsep(&args, ",")) != NULL) { - - p = param; - - while((*p != '\0') && (*p != '=')) - p++; - - if(p && strlen(p)) { - int param_num = 0; - - *p++ = '\0'; - - while(pobj.properties_names[param_num] - && strcasecmp(pobj.properties_names[param_num], param)) - param_num++; - - if(pobj.properties_names[param_num]) { - - pobj.param = pobj.descr->parameter; - pobj.param += param_num; - pobj.readonly = pobj.param->readonly; - - switch(pobj.param->type) { - case POST_PARAM_TYPE_INT: - if(!pobj.readonly) { - if(pobj.param->enum_values) { - char **values = pobj.param->enum_values; - int i = 0; - - while(values[i]) { - if(!strcasecmp(values[i], p)) { - *(int *)(pobj.param_data + pobj.param->offset) = i; - break; - } - i++; - } - - if( !values[i] ) - *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); - } else { - *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); - } - _pplugin_update_parameter(&pobj); - } - break; - - case POST_PARAM_TYPE_DOUBLE: - if(!pobj.readonly) { - *(double *)(pobj.param_data + pobj.param->offset) = strtod(p, &p); - _pplugin_update_parameter(&pobj); - } - break; - - case POST_PARAM_TYPE_CHAR: - case POST_PARAM_TYPE_STRING: - if(!pobj.readonly) { - if(pobj.param->type == POST_PARAM_TYPE_CHAR) { - int maxlen = pobj.param->size / sizeof(char); - - snprintf((char *)(pobj.param_data + pobj.param->offset), maxlen, "%s", p); - _pplugin_update_parameter(&pobj); - } - else - fprintf(stderr, "parameter type POST_PARAM_TYPE_STRING not supported yet.\n"); - } - break; - - case POST_PARAM_TYPE_STRINGLIST: /* unsupported */ - if(!pobj.readonly) - fprintf(stderr, "parameter type POST_PARAM_TYPE_STRINGLIST not supported yet.\n"); - break; - - case POST_PARAM_TYPE_BOOL: - if(!pobj.readonly) { - *(int *)(pobj.param_data + pobj.param->offset) = ((int) strtol(p, &p, 10)) ? 1 : 0; - _pplugin_update_parameter(&pobj); - } - break; - } - } else { - LOGMSG("Unknown post plugin parameter %s !", param); - } - } - } - - i = 0; - - while(pobj.properties_names[i]) { - free(pobj.properties_names[i]); - i++; - } - - free(pobj.properties_names); - } - - free(pobj.param_data); - } -} - -/* -post <name>:option1=value1,option2=value2... */ -static post_element_t **pplugin_parse_and_load(fe_t *fe, - int plugin_type, - const char *pchain, - int *post_elements_num) -{ - post_element_t **post_elements = NULL; - - *post_elements_num = 0; - - if(pchain && strlen(pchain)) { - char *post_chain, *freeme, *p; - - freeme = post_chain = strdup(pchain); - - while((p = xine_strsep(&post_chain, ";"))) { - - if(p && strlen(p)) { - char *plugin, *args = NULL; - xine_post_t *post; - - while(*p == ' ') - p++; - - plugin = strdup(p); - - if((p = strchr(plugin, ':'))) - *p++ = '\0'; - - if(p && (strlen(p) > 1)) - args = p; -#if 0 - post = xine_post_init(fe->xine, plugin, 0, - &fe->audio_port, &fe->video_port); -#else - if(plugin_type == XINE_POST_TYPE_VIDEO_COMPOSE) { - post = xine_post_init(fe->xine, plugin, 2, - &fe->audio_port, &fe->video_port); - } else - post = xine_post_init(fe->xine, plugin, 0, - &fe->audio_port, &fe->video_port); -#endif - - if (post && plugin_type) { - if (post->type != plugin_type) { - xine_post_dispose(fe->xine, post); - post = NULL; - } - } - - if(post) { - - if(!(*post_elements_num)) - post_elements = (post_element_t **) calloc(2, sizeof(post_element_t *)); - else - post_elements = (post_element_t **) - realloc(post_elements, sizeof(post_element_t *) * ((*post_elements_num) + 2)); - - post_elements[(*post_elements_num)] = calloc(1, sizeof(post_element_t)); - post_elements[(*post_elements_num)]->post = post; - post_elements[(*post_elements_num)]->name = strdup(plugin); -#if 1 - post_elements[(*post_elements_num)]->args = args ? strdup(args) : NULL; - post_elements[(*post_elements_num)]->enable = 0; -#endif - (*post_elements_num)++; - post_elements[(*post_elements_num)] = NULL; - - __pplugin_update_parameters(post, args); - } - - free(plugin); - } - } - free(freeme); - } - - return post_elements; -} - -void pplugin_parse_and_store_post(fe_t *fe, int plugin_type, - const char *post_chain) -{ - post_element_t ***_post_elements; - int *_post_elements_num; - post_element_t **posts = NULL; - int num; - - switch(plugin_type) { - case XINE_POST_TYPE_VIDEO_FILTER: - _post_elements = &fe->post_video_elements; - _post_elements_num = &fe->post_video_elements_num; - break; - case XINE_POST_TYPE_VIDEO_COMPOSE: - _post_elements = &fe->post_pip_elements; - _post_elements_num = &fe->post_pip_elements_num; - break; - case XINE_POST_TYPE_AUDIO_VISUALIZATION: - _post_elements = &fe->post_vis_elements; - _post_elements_num = &fe->post_vis_elements_num; - break; - default: - _post_elements = &fe->post_audio_elements; - _post_elements_num = &fe->post_audio_elements_num; - break; - } - - if((posts = pplugin_parse_and_load(fe, plugin_type, post_chain, &num))) { - if(*_post_elements_num) { - int i; - int ptot = *_post_elements_num + num; - - *_post_elements = (post_element_t **) realloc(*_post_elements, - sizeof(post_element_t *) * (ptot + 1)); - for(i = *_post_elements_num; i < ptot; i++) - (*_post_elements)[i] = posts[i - *_post_elements_num]; - - (*_post_elements)[i] = NULL; - (*_post_elements_num) += num; - } - else { - *_post_elements = posts; - *_post_elements_num = num; - } -#if 1 - if(SysLogLevel > 2) { - /* dump list of all loaded plugins */ - int ptot = *_post_elements_num; - int i; - char s[4096]=""; - for(i=0; i<ptot; i++) - if((*_post_elements)[i]) - if(((*_post_elements)[i])->post) { - if(((*_post_elements)[i])->enable) - strcat(s, "*"); - if(((*_post_elements)[i])->name) - strcat(s, ((*_post_elements)[i])->name); - else - strcat(s, "<no name!>"); - strcat(s, " "); - } - LOGDBG(" loaded plugins (type %d.%d): %s", - (plugin_type>>16), (plugin_type&0xffff), s); - } -#endif - } -} - - -void vpplugin_parse_and_store_post(fe_t *fe, const char *post_chain) -{ - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_FILTER, post_chain); - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_COMPOSE, post_chain); -} - - -void applugin_parse_and_store_post(fe_t *fe, const char *post_chain) -{ - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_FILTER, post_chain); - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_VISUALIZATION, post_chain); -} - - -static void _vpplugin_unwire(fe_t *fe) -{ - xine_post_out_t *vo_source; - vo_source = xine_get_video_source(fe->video_source); - (void) xine_post_wire_video_port(vo_source, fe->video_port); -} - - -static void _applugin_unwire(fe_t *fe) -{ - xine_post_out_t *ao_source; - ao_source = xine_get_audio_source(fe->audio_source); - (void) xine_post_wire_audio_port(ao_source, fe->audio_port); -} - - -static void _vpplugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) -{ - if(post_elements_num) { - xine_post_out_t *vo_source; - int i = 0; - - for(i = (post_elements_num - 1); i >= 0; i--) { - const char *const *outs = xine_post_list_outputs(post_elements[i]->post); - const xine_post_out_t *vo_out = xine_post_output(post_elements[i]->post, (char *) *outs); - if(i == (post_elements_num - 1)) { - LOGDBG(" wiring %10s[out] -> [in]video_out", post_elements[i]->name); - xine_post_wire_video_port((xine_post_out_t *) vo_out, fe->video_port); - } - else { - const xine_post_in_t *vo_in; - int err; - - /* look for standard input names */ - vo_in = xine_post_input(post_elements[i + 1]->post, "video"); - if( !vo_in ) - vo_in = xine_post_input(post_elements[i + 1]->post, "video in"); - - LOGDBG(" wiring %10s[out] -> [in]%-10s ", - post_elements[i]->name, post_elements[i+1]->name); - err = xine_post_wire((xine_post_out_t *) vo_out, - (xine_post_in_t *) vo_in); - } - } - - if(fe->post_pip_enable && - !strcmp(post_elements[0]->name, "mosaico") && - fe->pip_stream) { - vo_source = xine_get_video_source(fe->pip_stream); - LOGDBG(" wiring %10s[out] -> [in1]%-10s ", "pip stream", post_elements[0]->name); - xine_post_wire_video_port(vo_source, - post_elements[0]->post->video_input[1]); - } - - vo_source = xine_get_video_source(fe->video_source); - LOGDBG(" wiring %10s[out] -> [in]%-10s", "stream", post_elements[0]->name); - xine_post_wire_video_port(vo_source, - post_elements[0]->post->video_input[0]); - } -} - - -static void _applugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) -{ - if(post_elements_num) { - xine_post_out_t *ao_source; - int i = 0; - - for(i = (post_elements_num - 1); i >= 0; i--) { - const char *const *outs = xine_post_list_outputs(post_elements[i]->post); - const xine_post_out_t *ao_out = xine_post_output(post_elements[i]->post, (char *) *outs); - - if(i == (post_elements_num - 1)) { - LOGDBG(" wiring %10s[out] -> [in]audio_out", post_elements[i]->name); - xine_post_wire_audio_port((xine_post_out_t *) ao_out, fe->audio_port); - } - else { - const xine_post_in_t *ao_in; - int err; - - /* look for standard input names */ - ao_in = xine_post_input(post_elements[i + 1]->post, "audio"); - if( !ao_in ) - ao_in = xine_post_input(post_elements[i + 1]->post, "audio in"); - - LOGDBG(" wiring %10s[out] -> [in]%-10s ", - post_elements[i]->name, post_elements[i+1]->name); - err = xine_post_wire((xine_post_out_t *) ao_out, (xine_post_in_t *) ao_in); - } - } - - ao_source = xine_get_audio_source(fe->audio_source); - LOGDBG(" wiring %10s[out] -> [in]%-10s", "stream", post_elements[0]->name); - xine_post_wire_audio_port(ao_source, post_elements[0]->post->audio_input[0]); - } -} - -static post_element_t **_pplugin_join_deinterlace_and_post_elements(fe_t *fe, int *post_elements_num) -{ - post_element_t **post_elements; - int i = 0, j = 0, n = 0, p = 0; - static const char *order[] = {"autocrop", "thread", "tvtime", "swscale", NULL}; - - *post_elements_num = 0; - if( fe->post_video_enable ) - *post_elements_num += fe->post_video_elements_num; - - if( fe->post_pip_enable ) - *post_elements_num += fe->post_pip_elements_num; - - if( *post_elements_num == 0 ) - return NULL; - - post_elements = calloc( (*post_elements_num), sizeof(post_element_t *)); - - if(fe->post_pip_enable) - for( i = 0; i < fe->post_pip_elements_num; i++ ) { - if(fe->post_pip_elements[i]->enable) - post_elements[i+j-n] = fe->post_pip_elements[i]; - else - n++; - } - - if(fe->post_video_enable) - for( j = 0; j < fe->post_video_elements_num; j++ ) { - if(fe->post_video_elements[j]->enable) { - post_elements[i+j-n] = fe->post_video_elements[j]; - } else - n++; - } - - *post_elements_num -= n; - if( *post_elements_num == 0 ) { - free(post_elements); - return NULL; - } - - /* in some special cases order is important. By default plugin order - * in post plugin chain is post plugin loading order. - * But, we want: - * - * 1. autocrop - less data to process for other plugins - * - accepts only YV12 - * 2. deinterlace - blur etc. makes deinterlacing difficult. - * - upscales chroma (YV12->YUY2) in some modes. - * 3. anything else - * - * So let's move those two to beginning ... - */ - n = 0; - while(order[p]) { - for(i = 0; i<*post_elements_num; i++) - if(!strcmp(post_elements[i]->name, order[p])) { - if(i != n) { - post_element_t *tmp = post_elements[i]; - for(j=i; j>n; j--) - post_elements[j] = post_elements[j-1]; - post_elements[n] = tmp; - LOGDBG(" moved %s to post slot %d", order[p], n); - } - n++; - break; - } - p++; - } - - return post_elements; -} - -static post_element_t **_pplugin_join_visualization_and_post_elements(fe_t *fe, int *post_elements_num) -{ - post_element_t **post_elements; - int i = 0, j = 0, n = 0; - - *post_elements_num = 0; - if( fe->post_audio_enable ) - *post_elements_num += fe->post_audio_elements_num; - - if( fe->post_vis_enable ) - *post_elements_num += fe->post_vis_elements_num; - - if( *post_elements_num == 0 ) - return NULL; - - post_elements = calloc( (*post_elements_num), sizeof(post_element_t *)); - - if(fe->post_audio_enable) - for( j = 0; j < fe->post_audio_elements_num; j++ ) { - if(fe->post_audio_elements[j]->enable) - post_elements[i+j-n] = fe->post_audio_elements[j]; - else - n++; - } - - if(fe->post_vis_enable) - for( i = 0; i < fe->post_vis_elements_num; i++ ) { - if(fe->post_vis_elements[i]->enable) - post_elements[i+j-n] = fe->post_vis_elements[i]; - else - n++; - } - - *post_elements_num -= n; - if( *post_elements_num == 0 ) { - free(post_elements); - return NULL; - } - - return post_elements; -} - -static void _vpplugin_rewire(fe_t *fe) -{ - static post_element_t **post_elements; - int post_elements_num; - - post_elements = _pplugin_join_deinterlace_and_post_elements(fe, &post_elements_num); - - if( post_elements ) { - _vpplugin_rewire_from_post_elements(fe, post_elements, post_elements_num); - - free(post_elements); - } -} - -static void _applugin_rewire(fe_t *fe) -{ - static post_element_t **post_elements; - int post_elements_num; - - post_elements = _pplugin_join_visualization_and_post_elements(fe, &post_elements_num); - - if( post_elements ) { - _applugin_rewire_from_post_elements(fe, post_elements, post_elements_num); - - free(post_elements); - } -} - -void vpplugin_rewire_posts(fe_t *fe) -{ - /*TRACELINE;*/ - _vpplugin_unwire(fe); - _vpplugin_rewire(fe); -} - -void applugin_rewire_posts(fe_t *fe) -{ - /*TRACELINE;*/ - _applugin_unwire(fe); - _applugin_rewire(fe); -} - -static int _pplugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, - post_element_t **post_elements, - int post_elements_num, - int *found) -{ - int i, result = 0; - - for(i=0; i<post_elements_num; i++) - if(post_elements[i]) - if(!strcmp(post_elements[i]->name, name)) { - if(post_elements[i]->enable == 0) { - post_elements[i]->enable = 1; - result = 1; - } - - *found = 1; - - if(args && *args) { - if(post_elements[i]->enable != 2) { - char *tmp = strdup(args); - __pplugin_update_parameters(post_elements[i]->post, tmp); - free(tmp); - if(post_elements[i]->args) - free(post_elements[i]->args); - post_elements[i]->args = strdup(args); - } else { - LOGDBG(" * enable post %s, parameters fixed in command line.", name); - LOGDBG(" requested: %s", args ? : "none"); - LOGDBG(" using : %s", post_elements[i]->args ? : "none"); - } - } - } - - return result; -} - -static int _vpplugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, int *found) -{ - int result = 0; - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_video_elements, - fe->post_video_elements_num, found); - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_pip_elements, - fe->post_pip_elements_num, found); - return result; -} - -static int _applugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, int *found) -{ - int result = 0; - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_audio_elements, - fe->post_audio_elements_num, found); - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_vis_elements, - fe->post_vis_elements_num, found); - return result; -} - -static char * _pp_name_strdup(const char *initstr) -{ - char *name = strdup(initstr), *pt; - - if(NULL != (pt = strchr(name, ':'))) - *pt = 0; - - return name; -} - -static const char * _pp_args(const char *initstr) -{ - char *pt = strchr(initstr, ':'); - if(pt && *(pt+1)) - return pt+1; - return NULL; -} - -int vpplugin_enable_post(post_plugins_t *fe, const char *initstr, - int *found) -{ - char *name = _pp_name_strdup(initstr); - const char *args = _pp_args(initstr); - - int result = _vpplugin_enable_post(fe, name, args, found); - - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - - if(!*found) { - LOGDBG(" * loading post %s", initstr); - vpplugin_parse_and_store_post(fe, initstr); - result = _vpplugin_enable_post(fe, name, NULL, found); - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - } - - if(result) - _vpplugin_unwire(fe); - - free(name); - return result; -} - -int applugin_enable_post(post_plugins_t *fe, const char *initstr, - int *found) -{ - const char * args = _pp_args(initstr); - char *name = _pp_name_strdup(initstr); - - int result = _applugin_enable_post(fe, name, args, found); - - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - - if(!*found) { - LOGDBG(" * loading post %s", initstr); - applugin_parse_and_store_post(fe, initstr); - result = _applugin_enable_post(fe, name, NULL, found); - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - } - - if(result) - _applugin_unwire(fe); - - free(name); - return result; -} - -static int _pplugin_disable_post(post_plugins_t *fe, const char *name, - post_element_t **post_elements, - int post_elements_num) -{ - int i, result = 0; - /*TRACELINE;*/ - if(post_elements) - for(i = 0; i < post_elements_num; i++) - if(post_elements[i]) - if(!name || !strcmp(post_elements[i]->name, name)) - if(post_elements[i]->enable == 1) { - post_elements[i]->enable = 0; - result = 1; - } - return result; -} - -int vpplugin_disable_post(post_plugins_t *fe, const char *name) -{ - /*TRACELINE;*/ - if(_pplugin_disable_post(fe, name, fe->post_video_elements, - fe->post_video_elements_num) || - _pplugin_disable_post(fe, name, fe->post_pip_elements, - fe->post_pip_elements_num)) { - _vpplugin_unwire(fe); - return 1; - } - return 0; -} - -int applugin_disable_post(post_plugins_t *fe, const char *name) -{ - /*TRACELINE;*/ - if(_pplugin_disable_post(fe, name, fe->post_audio_elements, - fe->post_audio_elements_num) || - _pplugin_disable_post(fe, name, fe->post_vis_elements, - fe->post_vis_elements_num)) { - _applugin_unwire(fe); - return 1; - } - return 0; -} - -static int _pplugin_unload_post(post_plugins_t *fe, const char *name, - post_element_t ***post_elements, - int *post_elements_num) -{ - /* does not unwrire plugins ! */ - int i, j, result = 0; - /*TRACELINE;*/ - - if(!*post_elements || !*post_elements_num) - return 0; - - for(i=0; i < *post_elements_num; i++) { - if((*post_elements)[i]) { - if(!name || !strcmp((*post_elements)[i]->name, name)) { - - if((*post_elements)[i]->enable == 0 || !name) { - xine_post_dispose(fe->xine, (*post_elements)[i]->post); - - free((*post_elements)[i]->name); - - if((*post_elements)[i]->args) - free((*post_elements)[i]->args); - - free((*post_elements)[i]); - - for(j=i; j < *post_elements_num - 1; j++) - (*post_elements)[j] = (*post_elements)[j+1]; - - (*post_elements_num) --; - (*post_elements)[(*post_elements_num)] = 0; - - result = 1; - i--; - - } else { - LOGDBG("Unload %s failed: plugin enabled and in use", - (*post_elements)[i]->name); - } - } - } - } - - if(*post_elements_num <= 0) { - if(*post_elements) - free(*post_elements); - *post_elements = NULL; - } - - return result; -} - -int vpplugin_unload_post(post_plugins_t *fe, const char *name) -{ - int result = vpplugin_disable_post(fe, name); - - /* unload already disabled plugins too (result=0) */ - _pplugin_unload_post(fe, name, &fe->post_video_elements, - &fe->post_video_elements_num); - _pplugin_unload_post(fe, name, &fe->post_pip_elements, - &fe->post_pip_elements_num); - - /* result indicates only unwiring condition, not unload result */ - return result; -} - -int applugin_unload_post(post_plugins_t *fe, const char *name) -{ - int result = applugin_disable_post(fe, name); - - /* unload already disabled plugins too (result=0) */ - _pplugin_unload_post(fe, name, &fe->post_audio_elements, - &fe->post_audio_elements_num); - _pplugin_unload_post(fe, name, &fe->post_vis_elements, - &fe->post_vis_elements_num); - - /* result indicates only unwiring condition, not unload result */ - return result; -} - - -/* end of post.c */ - diff --git a/xine/post.h b/xine/post.h deleted file mode 100644 index 355e8e2c..00000000 --- a/xine/post.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2003 by Dirk Meyer - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * Modified for xineliboutput by Petri Hintukainen, 2006 - * - */ - -#ifndef POST_HH -#define POST_HH - -#include <xine.h> -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/plugin_catalog.h> - -typedef struct { - xine_post_t *post; - char *name; - char *args; - int enable; /* 0 - disabled, 1 - enabled, 2 - can't disable */ -} post_element_t; - - -typedef struct post_plugins_s post_plugins_t; - -struct post_plugins_s { - - /* frontend data */ - char *static_post_plugins; /* post plugins from command line; always on */ - xine_stream_t *video_source; /* stream to take video from */ - xine_stream_t *audio_source; /* stream to take audio from */ - xine_stream_t *pip_stream; /* pip stream */ - - /* xine */ - xine_t *xine; - xine_video_port_t *video_port; - xine_audio_port_t *audio_port; - - /* post.c internal use */ - int post_audio_elements_num; - int post_video_elements_num; - int post_vis_elements_num; - int post_pip_elements_num; - - post_element_t **post_audio_elements; - post_element_t **post_video_elements; - post_element_t **post_vis_elements; /* supports only one */ - post_element_t **post_pip_elements; /* supports only one and two input */ - - int post_audio_enable; - int post_video_enable; - int post_vis_enable; - int post_pip_enable; -}; - - -void vpplugin_rewire_posts(post_plugins_t *fe); -void applugin_rewire_posts(post_plugins_t *fe); - -/* load and config post plugin(s) */ -/* post == "plugin:arg1=val1,arg2=val2;plugin2..." */ -void vpplugin_parse_and_store_post(post_plugins_t *fe, const char *post); -void applugin_parse_and_store_post(post_plugins_t *fe, const char *post); - -/* enable (and load if not loaded), but don't rewire */ -/* result indicates only unwiring condition, not enable result */ -/* -> if result <> 0, something was enabled and post chain is unwired */ -int vpplugin_enable_post(post_plugins_t *fe, const char *name, int *found); -int applugin_enable_post(post_plugins_t *fe, const char *name, int *found); - -/* disable (and unwire if found), but don't unload */ -/* result indicates only unwiring condition, not disable result */ -int vpplugin_disable_post(post_plugins_t *fe, const char *name); -int applugin_disable_post(post_plugins_t *fe, const char *name); - -/* unload (and unwire) plugin(s) */ -/* result indicates only unwiring condition, not unload result */ -int vpplugin_unload_post(post_plugins_t *fe, const char *name); -int applugin_unload_post(post_plugins_t *fe, const char *name); - -#endif - -/* end of post.h */ diff --git a/xine/post_util.h b/xine/post_util.h deleted file mode 100644 index a539d31d..00000000 --- a/xine/post_util.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * post_util.h: post plugin utility functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: post_util.h,v 1.5 2008-12-14 00:52:35 phintuka Exp $ - * - */ - -#if POST_PLUGIN_IFACE_VERSION < 9 -# warning POST_PLUGIN_IFACE_VERSION < 9 not supported ! -#endif -#if POST_PLUGIN_IFACE_VERSION > 10 -# warning POST_PLUGIN_IFACE_VERSION > 10 not supported ! -#endif - -/* - * class util prototypes - */ - -static void *init_plugin(xine_t *xine, void *data); -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *get_identifier(post_class_t *class_gen); -static char *get_description(post_class_t *class_gen); -static void class_dispose(post_class_t *class_gen); -#endif - -/* required from plugin: */ -static post_plugin_t *open_plugin(post_class_t *class_gen, int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target); - -/* - * plugin util prototypes - */ - -static int dispatch_draw(vo_frame_t *frame, xine_stream_t *stream); -static int intercept_frame_yuy(post_video_port_t *port, vo_frame_t *frame); -static int post_draw(vo_frame_t *frame, xine_stream_t *stream); -#ifdef ENABLE_SLICED -static void dispatch_slice(vo_frame_t *vo_img, uint8_t **src); -#endif - -/* required from plugin: */ -static vo_frame_t *got_frame(vo_frame_t *frame); -static void draw_internal(vo_frame_t *frame, vo_frame_t *new_frame); - - -/* - * class utils - */ - -static void *init_plugin(xine_t *xine, void *data) -{ - post_class_t *class = calloc(1, sizeof(post_class_t)); - - if (!class) - return NULL; - - class->open_plugin = open_plugin; -#if POST_PLUGIN_IFACE_VERSION < 10 - class->get_identifier = get_identifier; - class->get_description = get_description; - class->dispose = class_dispose; -#else - class->identifier = PLUGIN_ID; - class->description = PLUGIN_DESCR; - class->dispose = default_post_class_dispose; -#endif - - return class; -} - -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *get_identifier(post_class_t *class_gen) -{ - return PLUGIN_ID; -} - -static char *get_description(post_class_t *class_gen) -{ - return PLUGIN_DESCR; -} - -static void class_dispose(post_class_t *class_gen) -{ - free(class_gen); -} -#endif - -/* - * plugin utils - */ - -#ifdef ENABLE_SLICED -static void dispatch_slice(vo_frame_t *vo_img, uint8_t **src) -{ - if (vo_img->next->proc_slice) { - _x_post_frame_copy_down(vo_img, vo_img->next); - vo_img->next->proc_slice(vo_img->next, src); - _x_post_frame_copy_up(vo_img, vo_img->next); - } -} -#endif - -static int dispatch_draw(vo_frame_t *frame, xine_stream_t *stream) -{ - int skip; - _x_post_frame_copy_down(frame, frame->next); - skip = frame->next->draw(frame->next, stream); - _x_post_frame_copy_up(frame, frame->next); - return skip; -} - -static int intercept_frame_yuy(post_video_port_t *port, vo_frame_t *frame) -{ - return (frame->format == XINE_IMGFMT_YV12 || frame->format == XINE_IMGFMT_YUY2); -} - -static int post_draw(vo_frame_t *frame, xine_stream_t *stream) -{ - vo_frame_t *new_frame; - int skip; - - if (frame->bad_frame) - return dispatch_draw(frame, stream); - - new_frame = got_frame(frame); - - if (!new_frame) - return dispatch_draw(frame, stream); - - _x_post_frame_copy_down(frame, new_frame); - - draw_internal(frame, new_frame); - - skip = new_frame->draw(new_frame, stream); - _x_post_frame_copy_up(frame, new_frame); - new_frame->free(new_frame); - - return skip; -} - diff --git a/xine/ts2es.c b/xine/ts2es.c deleted file mode 100644 index bb06d3ea..00000000 --- a/xine/ts2es.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ts2es.c: demux MPEG-TS -> ES - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts2es.c,v 1.5 2009-08-25 10:09:20 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/buffer.h> - -#include "../tools/ts.h" -#include "../tools/pes.h" - -#include "ts2es.h" - -#define LOG_MODULENAME "[demux_vdr] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - - -struct ts2es_s { - fifo_buffer_t *fifo; - uint32_t stream_type; - uint32_t xine_buf_type; - - buf_element_t *buf; - int pes_start; - int first_pusi_seen; - int video; - int64_t pts; -}; - - -static void ts2es_parse_pes(ts2es_t *this) -{ - if (!DATA_IS_PES(this->buf->content)) { - LOGMSG("ts2es: payload not PES ?"); - return; - } - - /* parse PES header */ - uint hdr_len = PES_HEADER_LEN(this->buf->content); - uint8_t pes_pid = this->buf->content[3]; - uint pes_len = (this->buf->content[4] << 8) | this->buf->content[5]; - - /* parse PTS */ - this->buf->pts = pes_get_pts(this->buf->content, this->buf->size); - if(this->buf->pts >= 0) - this->pts = this->buf->pts; - else - this->pts = 0; - - /* strip PES header */ - this->buf->content += hdr_len; - this->buf->size -= hdr_len; - - /* parse substream header */ - - if (pes_pid != PRIVATE_STREAM1) - return; - - /* RAW AC3 audio ? -> do nothing */ - if (this->stream_type == STREAM_AUDIO_AC3) { - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - /* AC3 syncword in beginning of PS1 payload ? */ - if (this->buf->content[0] == 0x0B && - this->buf->content[1] == 0x77) { - /* --> RAW AC3 audio - do nothing */ - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - /* audio in PS1 */ - if (this->stream_type == ISO_13818_PES_PRIVATE) { - - if ((this->buf->content[0] & 0xf0) == 0x80) { - /* AC3, strip substream header */ - this->buf->content += 4; - this->buf->size -= 4; - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - if ((this->buf->content[0] & 0xf0) == 0xa0) { - /* PCM, strip substream header */ - int pcm_offset; - for (pcm_offset=0; ++pcm_offset < this->buf->size-1 ; ) { - if (this->buf->content[pcm_offset] == 0x01 && - this->buf->content[pcm_offset+1] == 0x80 ) { /* START */ - pcm_offset += 2; - break; - } - } - this->buf->content += pcm_offset; - this->buf->size -= pcm_offset; - - this->xine_buf_type |= BUF_AUDIO_LPCM_BE; - this->buf->type = this->xine_buf_type; - return; - } - - LOGMSG("ts2es: unhandled PS1 substream 0x%x", this->buf->content[0]); - return; - } - - /* DVB SPU */ - if (this->stream_type == STREAM_DVBSUB) { - if (this->buf->content[0] != 0x20 || - this->buf->content[1] != 0x00) - LOGMSG("ts2es: DVB SPU, invalid PES substream header"); - this->buf->decoder_info[2] = pes_len - hdr_len - 3 + 9; - return; - } -} - -buf_element_t *ts2es_put(ts2es_t *this, uint8_t *data, fifo_buffer_t *src_fifo) -{ - buf_element_t *result = NULL; - int bytes = ts_PAYLOAD_SIZE(data); - int pusi = ts_PAYLOAD_START(data); - - if (ts_HAS_ERROR(data)) { - LOGDBG("ts2es: transport error"); - return NULL; - } - if (!ts_HAS_PAYLOAD(data)) { - LOGDBG("ts2es: no payload, size %d", bytes); - return NULL; - } - - /* handle new payload unit */ - if (pusi) { - this->first_pusi_seen = 1; - this->pes_start = 1; - if (this->buf) { - - this->buf->decoder_flags |= BUF_FLAG_FRAME_END; - this->buf->pts = this->pts; - - result = this->buf; - this->buf = NULL; - } - } - - /* need new buffer ? */ - if (!this->buf) { - /* discard data until first payload start indicator */ - if (!this->first_pusi_seen) - return NULL; - - if (src_fifo && src_fifo != this->fifo) { - if (!this->video) - this->buf = this->fifo->buffer_pool_try_alloc(this->fifo); - if (!this->buf) - this->buf = src_fifo->buffer_pool_try_alloc(src_fifo); - if (!this->buf) - this->buf = this->fifo->buffer_pool_alloc(this->fifo); - } else { - this->buf = this->fifo->buffer_pool_alloc(this->fifo); - } - - this->buf->type = this->xine_buf_type; - this->buf->decoder_info[0] = 1; - } - - /* strip ts header */ - data += TS_SIZE - bytes; - - /* copy payload */ - memcpy(this->buf->content + this->buf->size, data, bytes); - this->buf->size += bytes; - - /* parse PES header */ - if (this->pes_start) { - this->pes_start = 0; - - ts2es_parse_pes(this); - } - - /* split large packets */ - if ((this->video && this->buf->size >= 2048+64-TS_SIZE) || - this->buf->size >= this->buf->max_size-TS_SIZE) { - - this->buf->pts = this->pts; - - result = this->buf; - this->buf = NULL; - } - - return result; -} - -void ts2es_flush(ts2es_t *this) -{ - if (this->buf) { - - this->buf->decoder_flags |= BUF_FLAG_FRAME_END; - this->buf->pts = this->pts; - - this->fifo->put (this->fifo, this->buf); - this->buf = NULL; - } -} - -void ts2es_dispose(ts2es_t *data) -{ - if (data) { - if (data->buf) - data->buf->free_buffer(data->buf); - free(data); - } -} - -ts2es_t *ts2es_init(fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index) -{ - ts2es_t *data = calloc(1, sizeof(ts2es_t)); - data->fifo = dst_fifo; - - data->stream_type = stream_type; - - switch(stream_type) { - /* VIDEO (PES streams 0xe0...0xef) */ - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case STREAM_VIDEO_MPEG: - data->xine_buf_type = BUF_VIDEO_MPEG; - break; - case ISO_14496_PART2_VIDEO: - data->xine_buf_type = BUF_VIDEO_MPEG4; - break; - case ISO_14496_PART10_VIDEO: - data->xine_buf_type = BUF_VIDEO_H264; - break; - - /* AUDIO (PES streams 0xc0...0xdf) */ - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - data->xine_buf_type = BUF_AUDIO_MPEG; - break; - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - data->xine_buf_type = BUF_AUDIO_AAC; - break; - - /* AUDIO (PES stream 0xbd) */ - case ISO_13818_PES_PRIVATE: - data->xine_buf_type = 0; - /* detect from PES substream header */ - break; - - /* DVB SPU (PES stream 0xbd) */ - case STREAM_DVBSUB: - data->xine_buf_type = BUF_SPU_DVB; - break; - - /* RAW AC3 */ - case STREAM_AUDIO_AC3: - data->xine_buf_type = BUF_AUDIO_A52; - break; - - default: - LOGMSG("ts2es: unknown stream type 0x%x", stream_type); - break; - } - - /* substream ID (audio/SPU) */ - data->xine_buf_type |= stream_index; - - if ((data->xine_buf_type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) - data->video = 1; - - return data; -} - diff --git a/xine/ts2es.h b/xine/ts2es.h deleted file mode 100644 index e009fc1c..00000000 --- a/xine/ts2es.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ts2es.h: demux MPEG-TS -> ES - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts2es.h,v 1.2 2009-08-18 10:04:32 phintuka Exp $ - * - */ - -#ifndef _DEMUX_XVDR_TS2ES_H_ -#define _DEMUX_XVDR_TS2ES_H_ - -typedef struct ts2es_s ts2es_t; - -ts2es_t *ts2es_init (fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index); -buf_element_t *ts2es_put (ts2es_t *ts2es, uint8_t *ts_packet, fifo_buffer_t *src_fifo); -void ts2es_flush (ts2es_t *ts2es); -void ts2es_dispose (ts2es_t *ts2es); - -#endif /* _DEMUX_XVDR_TS2ES_H_ */ diff --git a/xine/vo_hook.c b/xine/vo_hook.c deleted file mode 100644 index 89190b9c..00000000 --- a/xine/vo_hook.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * vo_hook.c: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_hook.c,v 1.5 2009-05-09 16:05:06 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> - -#define LOG_MODULENAME "[xine-vo ] " -#include "../logdefs.h" - -#include "vo_hook.h" -#include "vo_post.h" - -/* This module supports only video driver interface version 21 */ -#if (VIDEO_OUT_DRIVER_IFACE_VERSION < 21) -# error xine-lib VIDEO_OUT_DRIVER_IFACE_VERSION < 21 -#endif - - -/* - * default handlers - * - * - Forward function call to original driver - */ - -#define DEF_HANDLER3(RET, NAME, ARG1, ARG2, ARG3) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1, ARG2 a2, ARG3 a3) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1, a2, a3); \ -} - -#define DEF_HANDLER2(RET, NAME, ARG1, ARG2) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1, ARG2 a2) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1, a2); \ -} - -#define DEF_HANDLER1(RET, NAME, ARG1) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1); \ -} - -#define DEF_HANDLER0(RET, NAME) \ -RET vo_def_##NAME (vo_driver_t *self) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver); \ -} - -/* - * - */ - -DEF_HANDLER0(uint32_t, get_capabilities); -DEF_HANDLER0(vo_frame_t*, alloc_frame); - -void vo_def_update_frame_format (vo_driver_t *self, vo_frame_t *img, - uint32_t width, uint32_t height, - double ratio, int format, int flags) -{ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; - return this->orig_driver-> update_frame_format (this->orig_driver, img, width, height, ratio, format, flags); -} - -DEF_HANDLER1(void, display_frame, vo_frame_t * ); -DEF_HANDLER2(void, overlay_begin, vo_frame_t *, int ); -DEF_HANDLER2(void, overlay_blend, vo_frame_t *, vo_overlay_t * ); -DEF_HANDLER1(void, overlay_end, vo_frame_t *); -DEF_HANDLER1(int, get_property, int); -DEF_HANDLER2(int, set_property, int, int); -DEF_HANDLER3(void, get_property_min_max, int, int*, int*); -DEF_HANDLER2(int, gui_data_exchange, int, void * ); -DEF_HANDLER0(int, redraw_needed ); - -void vo_def_dispose(vo_driver_t *self) -{ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; - if (this->orig_driver) - this->orig_driver->dispose(this->orig_driver); - free(self); -} - -/* - * vo_def_hooks_init() - * - * initialize driver_hook_t with default handlers - * - */ -static void vo_proxy_hooks_init(vo_driver_t *drv, vo_driver_t *next_driver) -{ - drv->get_capabilities = drv->get_capabilities ?: vo_def_get_capabilities; - drv->alloc_frame = drv->alloc_frame ?: vo_def_alloc_frame; - drv->update_frame_format = drv->update_frame_format ?: vo_def_update_frame_format; - drv->display_frame = drv->display_frame ?: vo_def_display_frame; - - drv->get_property = drv->get_property ?: vo_def_get_property; - drv->set_property = drv->set_property ?: vo_def_set_property; - drv->get_property_min_max = drv->get_property_min_max ?: vo_def_get_property_min_max; - drv->gui_data_exchange = drv->gui_data_exchange ?: vo_def_gui_data_exchange; - drv->redraw_needed = drv->redraw_needed ?: vo_def_redraw_needed; - drv->dispose = drv->dispose ?: vo_def_dispose; - - /* drop old default handlers for OSD (OSD handlers are optional) */ - if (drv->overlay_begin == vo_def_overlay_begin) - drv->overlay_begin = NULL; - if (drv->overlay_blend == vo_def_overlay_blend) - drv->overlay_blend = NULL; - if (drv->overlay_end == vo_def_overlay_end) - drv->overlay_end = NULL; - - /* Set proxy handlers for OSD only if next driver has OSD handlers */ - if (!drv->overlay_begin && next_driver->overlay_begin) - drv->overlay_begin = vo_def_overlay_begin; - if (!drv->overlay_blend && next_driver->overlay_blend) - drv->overlay_blend = vo_def_overlay_blend; - if (!drv->overlay_end && next_driver->overlay_end) - drv->overlay_end = vo_def_overlay_end; - - drv->node = next_driver->node; /* ??? used only by plugin_loader ? */ -} - -/* - * - */ - -/* from xine-lib video_out.c */ -typedef struct { - xine_video_port_t vo; /* public part */ - vo_driver_t *driver; - /* ... */ -} vos_t; - -/* - * wire_video_driver() - * - */ -int wire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook) -{ - vo_driver_t *vos_driver = ((vos_t*)video_port)->driver; - - if (video_port->driver != vos_driver) { - LOGMSG("wire_video_driver() FAILED (vo_driver != vos_driver)"); - return 0; - } - - /*LOGMSG("wire_video_driver: vo_driver == vos_driver");*/ - - /* wire */ - - /* set proxy handlers for undefined methods */ - vo_proxy_hooks_init(hook, video_port->driver); - - /* append original driver chain to new driver */ - ((vo_driver_hook_t *)hook)->orig_driver = video_port->driver; - - /* push new driver to start of driver chain */ - video_port->driver = hook; - ((vos_t*)video_port)->driver = hook; - - return 1; -} - -/* - * unwire_video_driver() - * - */ -int unwire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook_gen, vo_driver_t *video_out) -{ - vo_driver_hook_t *hook = (vo_driver_hook_t*)hook_gen; - vo_driver_hook_t *next = (vo_driver_hook_t*)video_port->driver; - - if (next == hook) { - /* special handling for first entry */ - video_port->driver = next->orig_driver; - /* need to patch video_port private driver pointer too ... */ - ((vos_t*)video_port)->driver = next->orig_driver; - next->orig_driver = NULL; - return 1; - } - - vo_driver_hook_t *prev = next; - while (next && next != hook && (vo_driver_t*)next != video_out) { - prev = next; - next = (vo_driver_hook_t*)next->orig_driver; - } - - if (prev && next == hook) { - prev->orig_driver = next->orig_driver; - next->orig_driver = NULL; - return 1; - } - - return 0; -} diff --git a/xine/vo_hook.h b/xine/vo_hook.h deleted file mode 100644 index 0de93fd0..00000000 --- a/xine/vo_hook.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * vo_hook.h: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_hook.h,v 1.3 2008-12-14 01:14:54 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_HOOK_H -#define _XINELIBOUTPUT_VO_HOOK_H - -#include <xine/video_out.h> - -/* - * synchronous video post plugins - * internal API - */ - - -/* - * vo_driver_hook_t - * - * Used as base for video driver hooks - */ - -typedef struct driver_hook_s { - vo_driver_t vo; /* public part */ - vo_driver_t *orig_driver; -} vo_driver_hook_t; - -/* proxy handlers: forward call to original driver */ - -uint32_t vo_def_get_capabilities(vo_driver_t *self); -int vo_def_get_property(vo_driver_t *self, int prop); -int vo_def_set_property(vo_driver_t *self, int prop, int val); - -void vo_def_dispose(vo_driver_t *self); - - -#endif /* _XINELIBOUTPUT_VO_HOOK_H */ diff --git a/xine/vo_osdreorder.c b/xine/vo_osdreorder.c deleted file mode 100644 index 6fed9e3c..00000000 --- a/xine/vo_osdreorder.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * vo_osdreorder.c: OSD re-ordering video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdreorder.c,v 1.1 2009-03-17 12:14:41 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> - -#include "vo_props.h" -#include "vo_hook.h" - -/* - * osdreorder_hook_t - */ -typedef struct { - vo_driver_hook_t h; - - /* currently showing OSDs in new drawing order */ - vo_overlay_t *overlay[50]; - -} osdreorder_hook_t; - -/* - * - */ - -static int osd_level(vo_overlay_t *overlay) -{ - if (overlay->hili_rgb_clut != VDR_OSD_MAGIC /* not from vdr */) { - return 9999; - } - - /* VDR input plugin stores some control data in hili clut area */ - vdr_osd_extradata_t *data = (vdr_osd_extradata_t *)overlay->hili_color; - return data->layer; -} - -/* - * interface - */ - -/* - * override overlay_blend() - */ -static void osdreorder_overlay_blend (vo_driver_t *self, vo_frame_t *frame, vo_overlay_t *overlay) -{ - osdreorder_hook_t *this = (osdreorder_hook_t*)self; - int my_level = osd_level(overlay); - int i; - - /* search position */ - for (i = 0; this->overlay[i] && osd_level(this->overlay[i]) >= my_level; i++) - ; - - /* make room */ - if (this->overlay[i]) - memmove(&this->overlay[i+1], &this->overlay[i], (49-i)*sizeof(vo_overlay_t*)); - - this->overlay[i] = overlay; - return; -} - -/* - * override overlay_end() - */ -static void osdreorder_overlay_end (vo_driver_t *self, vo_frame_t *vo_img) -{ - osdreorder_hook_t *this = (osdreorder_hook_t*)self; - int i; - - for (i = 0; this->overlay[i]; i++) { - this->h.orig_driver->overlay_blend(this->h.orig_driver, vo_img, this->overlay[i]); - this->overlay[i] = NULL; - } - - /* redirect */ - if (this->h.orig_driver->overlay_end) - this->h.orig_driver->overlay_end(this->h.orig_driver, vo_img); -} - -/* - * init() - */ -vo_driver_t *osd_reorder_init(void) -{ - osdreorder_hook_t *this = calloc(1, sizeof(osdreorder_hook_t)); - - /* OSD interface */ - this->h.vo.overlay_blend = osdreorder_overlay_blend; - this->h.vo.overlay_end = osdreorder_overlay_end; - - return &this->h.vo; -} - diff --git a/xine/vo_osdreorder.h b/xine/vo_osdreorder.h deleted file mode 100644 index 15ec7a6b..00000000 --- a/xine/vo_osdreorder.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * vo_osdreorder.h: OSD re-ordering video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdreorder.h,v 1.1 2009-03-17 12:14:41 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_OSDREORDER_H -#define _XINELIBOUTPUT_VO_OSDREORDER_H - -vo_driver_t *osd_reorder_init(void); - -#endif /* _XINELIBOUTPUT_VO_OSDREORDER_H */ diff --git a/xine/vo_osdscaler.c b/xine/vo_osdscaler.c deleted file mode 100644 index d9562d9e..00000000 --- a/xine/vo_osdscaler.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * vo_osdscaler.c: OSD scaling video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdscaler.c,v 1.4 2009-05-27 08:37:06 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> -#ifdef SWBLEND -# include <xine/alphablend.h> -#endif - -#define LOG_MODULENAME "[osdscaler] " -#include "../logdefs.h" - -#include "vo_props.h" -#include "vo_hook.h" - -/*#define LOGOSD(x...) LOGMSG(x)*/ -#define LOGOSD(x...) - -typedef rle_elem_t xine_rle_elem_t; - -#include "../tools/rle.h" - - -/* Make sure our properties won't overlap with xine's properties */ -#if VO_NUM_PROPERTIES > VO_PROP_OSD_SCALING -# error VO_NUM_PROPERTIES > VO_PROP_OSD_SCALING -#endif - -#undef ABS -#define ABS(x) ((x)<0?-(x):(x)) - - -/* - * osd_data_t - * - * - cache scaled OSD data - */ - -typedef struct osd_data_s osd_data_t; - -struct osd_data_s { - /* original source */ - vo_overlay_t *source; - - /* scaled overlay */ - uint8_t scaled : 1; - vo_overlay_t ovl; - - /* for what output resolution overlay was scaled */ - uint16_t output_width; - uint16_t output_height; - - /* linked list */ - osd_data_t *next; -}; - -/* - * osd_data_dispose() - * - * - free() osd_data_t and all allocated memory - */ -static void osd_data_dispose(osd_data_t *data) -{ - if (data->scaled) - free(data->ovl.rle); - free(data); -} - -/* - * osd_data_clear() - * - * - free() whole linked list - */ -static void osd_data_clear(osd_data_t *data) -{ - if (data) { - if (data->next) - osd_data_clear(data->next); - osd_data_dispose(data); - } -} - -/* - * osd_data_remove() - * - * - remove (and free) specific osd_data_t item from linked list - */ -static void osd_data_remove(osd_data_t **list, osd_data_t *data) -{ - if (!list || !*list) - return; - - /* special handling for list head */ - if (data == *list) { - *list = data->next; - free(data); - return; - } - - osd_data_t *it = *list; - while (it) { - if (data == it->next) { - it->next = data->next; - free(data); - return; - } - it = it->next; - } -} - -/* - * osd_data_init() - * - * - allocate and fill new osd_data_t - * - */ -static osd_data_t *osd_data_init(vo_overlay_t *ovl, osd_data_t *next, - uint32_t factor_x, uint32_t factor_y) -{ - osd_data_t *data = calloc(1, sizeof(osd_data_t)); - - data->source = ovl; - data->next = next; - - memcpy(&data->ovl, ovl, sizeof(vo_overlay_t)); - - int num_rle = data->ovl.num_rle; - - /* new position and size */ - int x2 = ovl->x + ovl->width + 1; - int y2 = ovl->y + ovl->height + 1; - x2 = ((x2+1) * factor_x) >> 16; - y2 = ((y2+1) * factor_y) >> 16; - data->ovl.x = (ovl->x * factor_x) >> 16; - data->ovl.y = (ovl->y * factor_y) >> 16; - data->ovl.width = x2 - data->ovl.x - 1; - data->ovl.height = y2 - data->ovl.y - 1; - - data->ovl.rle = (rle_elem_t*) - rle_scale_nearest((struct xine_rle_elem_s*)ovl->rle, &num_rle, - ovl->width, ovl->height, - data->ovl.width, data->ovl.height); - data->ovl.num_rle = num_rle; - data->scaled = 1; - - LOGOSD("I: %d,%d %dx%d", ovl->x, ovl->y, ovl->width, ovl->height); - LOGOSD("O: %d,%d %dx%d", data->ovl.x, data->ovl.y, data->ovl.width, data->ovl.height); - - return data; -} - -/* - * osdscaler_hook_t - */ -typedef struct { - vo_driver_hook_t h; - - /* configuration */ - uint8_t enable; - uint8_t unscaled_supported; - uint8_t custom_extent_supported; - uint8_t argb_supported; - - /* current output */ - uint16_t output_width; - uint16_t output_height; - uint32_t factor_x; /* scaling factor << 16 */ - uint32_t factor_y; - uint16_t x_move; /* OSD displacement */ - uint16_t y_move; - - /* currently showing OSDs - pre-scaled data */ - osd_data_t *active_osds; - -} osdscaler_hook_t; - -/* - * - */ - -/* - * override overlay_begin() - */ -static void osdscaler_overlay_begin (vo_driver_t *self, vo_frame_t *frame, int changed) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - /* assume we're wired when called */ - if (!this->h.orig_driver) { - LOGMSG("osdscaler_overlay_begin: assertion this->h.orig_driver failed !"); - abort(); - } - - /* re-scale all if OSD changed */ - if (changed) { - LOGOSD("osdscaler_overlay_begin: changed = 1"); - osd_data_clear(this->active_osds); - this->active_osds = NULL; - this->unscaled_supported = (vo_def_get_capabilities(self) & VO_CAP_UNSCALED_OVERLAY); - /* VO_CAP_OSDSCALING == VO_CAP_CUSTOM_EXTENT_OVERLAY */ - this->custom_extent_supported = (vo_def_get_capabilities(self) & VO_CAP_OSDSCALING); - /* VO_CAP_ARGB == VO_CAP_ARGB_LAYER_OVERLAY */ - this->argb_supported = (vo_def_get_capabilities(self) & VO_CAP_ARGB); - } - - /* redirect */ - if (this->h.orig_driver->overlay_begin) - this->h.orig_driver->overlay_begin(this->h.orig_driver, frame, changed); -} - -static int check_for_scaling(osdscaler_hook_t *this, vo_frame_t *frame, vo_overlay_t *overlay) -{ - this->x_move = this->y_move = 0; - - if (!this->enable) - return 0; - - /* check for VDR OSD */ - if (overlay->hili_rgb_clut != VDR_OSD_MAGIC /* not from vdr */) { - LOGOSD("overlay: source not VDR"); - return 0; - } - - /* VDR input plugin stores some control data in hili clut area */ - vdr_osd_extradata_t *data = (vdr_osd_extradata_t *)overlay->hili_color; - int extent_width = data->extent_width; - int extent_height = data->extent_height; - - if (!data->scaling) - return 0; - -#if 0 - if (this->custom_extent_supported) { - /* let the "real" video driver do scaling */ - return 0; - } -#else -# ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - /* disable VDPAU HW scaler */ - overlay->extent_width = 0; - overlay->extent_height = 0; -# endif -#endif - - /* detect output size */ - if (overlay->unscaled && this->unscaled_supported) { - this->output_width = vo_def_get_property((vo_driver_t*)this, VO_PROP_WINDOW_WIDTH); - this->output_height = vo_def_get_property((vo_driver_t*)this, VO_PROP_WINDOW_HEIGHT); - } else { - this->output_width = frame->width; - this->output_height = frame->height; - /* check cropping */ - if (frame->crop_top > 0) this->output_height -= frame->crop_top; - if (frame->crop_bottom > 0) this->output_height -= frame->crop_bottom; - if (frame->crop_left > 0) this->output_width -= frame->crop_left; - if (frame->crop_right > 0) this->output_width -= frame->crop_right; - } - - /* check if scaling should be done */ - if (ABS(this->output_width - extent_width) > extent_width /20 || - ABS(this->output_height - extent_height) > extent_height/20 ) { - LOGOSD("scaling required"); - this->factor_x = 0x10000 * this->output_width / extent_width; - this->factor_y = 0x10000 * this->output_height / extent_height; - return 1; - } - - /* if no scaling was required, we may still need to re-center OSD */ - if(this->output_width != extent_width) - this->x_move = (this->output_width - extent_width)/2; - if(this->output_height != extent_height) - this->y_move = (this->output_height - extent_height)/2; - - return 0; -} - -static vo_overlay_t *scale_overlay(osdscaler_hook_t *this, vo_frame_t *frame, vo_overlay_t *overlay) -{ - if (check_for_scaling(this, frame, overlay)) { - - /* find old scaled OSD */ - osd_data_t *scaled = this->active_osds; - while (scaled && scaled->source != overlay) - scaled = scaled->next; - - /* output size changed since last scaling (need to re-scale) ? */ - if (scaled && - (scaled->output_width != this->output_width || - scaled->output_height != this->output_height)) { - - LOGOSD("re-scaling required: output size changed %dx%d -> %dx%d", - scaled->output_width, scaled->output_height, this->output_width, this->output_height); - - osd_data_remove(&this->active_osds, scaled); - scaled = NULL; - } - - /* not scaled found ? */ - if (!scaled) { - LOGOSD("scaling OSD"); - scaled = this->active_osds = osd_data_init(overlay, this->active_osds, - this->factor_x, this->factor_y); - scaled->output_width = this->output_width; - scaled->output_height = this->output_height; - } - - /* override */ - overlay = &scaled->ovl; - } - - return overlay; -} - - -/* - * interface - */ - -/* - * override overlay_blend() - */ -static void osdscaler_overlay_blend (vo_driver_t *self, vo_frame_t *frame, vo_overlay_t *overlay) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - overlay = scale_overlay(this, frame, overlay); - - /* redirect */ - if (this->h.orig_driver->overlay_blend) - this->h.orig_driver->overlay_blend(this->h.orig_driver, frame, overlay); -} - -/* - * override overlay_end() - */ -static void osdscaler_overlay_end (vo_driver_t *self, vo_frame_t *vo_img) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - /* redirect */ - if (this->h.orig_driver->overlay_end) - this->h.orig_driver->overlay_end(this->h.orig_driver, vo_img); -} - - -/* - * Management interface - */ - -/* - * override get_capabilities() - */ -static uint32_t osdscaler_get_capabilities(vo_driver_t *self) -{ - return vo_def_get_capabilities(self) | - VO_CAP_OSDSCALING; -} - -/* - * override get_property() - */ -static int osdscaler_get_property(vo_driver_t *self, int prop) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - switch (prop) { - case VO_PROP_OSD_SCALING: return this->enable; - default:; - } - - return vo_def_get_property(self, prop); -} - -/* - * override set_property() - */ -static int osdscaler_set_property(vo_driver_t *self, int prop, int val) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - switch (prop) { - case VO_PROP_OSD_SCALING: - if (this->enable != val) { - LOGOSD("osdscaler_set_property: enable %d->%d", this->enable, val); - this->enable = val?1:0; - } - return this->enable; - } - - return vo_def_set_property(self, prop, val); -} - - -/* - * dispose() - */ -static void osdscaler_dispose(vo_driver_t *self) -{ - osdscaler_hook_t *this = (osdscaler_hook_t *) self; - - osd_data_clear(this->active_osds); - - vo_def_dispose(self); -} - - -/* - * init() - */ -vo_driver_t *osdscaler_init(void) -{ - osdscaler_hook_t *this = calloc(1, sizeof(osdscaler_hook_t)); - - /* OSD interface */ - this->h.vo.overlay_begin = osdscaler_overlay_begin; - this->h.vo.overlay_blend = osdscaler_overlay_blend; - this->h.vo.overlay_end = osdscaler_overlay_end; - - /* management interface */ - this->h.vo.get_capabilities = osdscaler_get_capabilities; - this->h.vo.get_property = osdscaler_get_property; - this->h.vo.set_property = osdscaler_set_property; - - this->h.vo.dispose = osdscaler_dispose; - - /* initialize data */ - this->enable = 0; - - return &this->h.vo; -} - diff --git a/xine/vo_osdscaler.h b/xine/vo_osdscaler.h deleted file mode 100644 index fe7d21d0..00000000 --- a/xine/vo_osdscaler.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * vo_osdscaler.h: OSD scaling video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdscaler.h,v 1.1 2008-11-20 09:24:27 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_OSDSCALER_H -#define _XINELIBOUTPUT_VO_OSDSCALER_H - -vo_driver_t *osdscaler_init(void); - -#endif /* _XINELIBOUTPUT_VO_OSDSCALER_H */ diff --git a/xine/vo_post.h b/xine/vo_post.h deleted file mode 100644 index 8ed7b076..00000000 --- a/xine/vo_post.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * vo_post.h: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_post.h,v 1.3 2008-12-14 01:19:21 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_POST_H -#define _XINELIBOUTPUT_VO_POST_H - -#include <xine/video_out.h> - -/* - * synchronous video post plugins - * public API - */ - -/* Wire / unwire hook chain to video port */ -int wire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook); -int unwire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook, vo_driver_t *video_out); - -#endif /* _XINELIBOUTPUT_VO_POST_H */ diff --git a/xine/vo_props.h b/xine/vo_props.h deleted file mode 100644 index dc377dfc..00000000 --- a/xine/vo_props.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * vo_props.h: Extended video-out capabilities and properties - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_props.h,v 1.4 2009-03-17 12:20:33 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_VO_PROPS_H_ -#define XINELIBOUTPUT_VO_PROPS_H_ - -/* - * Extended vo capabilities - */ - -/* output can scale OSD */ -#ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - /* xine-lib 1.2 */ -# define VO_CAP_OSDSCALING VO_CAP_CUSTOM_EXTENT_OVERLAY -#else -# define VO_CAP_OSDSCALING 0x01000000 -#endif - -/* Output can blend ARGB surfaces */ -#ifdef VO_CAP_ARGB_LAYER_OVERLAY -# define VO_CAP_ARGB VO_CAP_ARGB_LAYER_OVERLAY -#else -# define VO_CAP_ARGB 0x02000000 -#endif - - -/* - * Extended vo properties - */ - -/* enable/disable OSD scaling */ -#define VO_PROP_OSD_SCALING 0x1001 - - -/* - * VDR OSD tagging and extra data - */ - -/* VDR OSD , stored in overlay hili_rgb_clut member */ -#define VDR_OSD_MAGIC -9999 - -/* VDR OSD extra data, stored in overlay hili clut data */ -typedef struct { - /* extent of reference coordinate system */ - uint16_t extent_width; - uint16_t extent_height; - /* overlay layer */ - uint32_t layer; - /* scaling: 0 - disable , 1...N - quality */ - uint8_t scaling; -} vdr_osd_extradata_t; - -#endif /* XINELIBOUTPUT_VO_PROPS_H_ */ diff --git a/xine/xvdr_metronom.c b/xine/xvdr_metronom.c deleted file mode 100644 index 1a2316ab..00000000 --- a/xine/xvdr_metronom.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * xvdr_metronom.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xvdr_metronom.c,v 1.1 2009-05-22 21:02:30 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/xine_internal.h> -#include <xine/metronom.h> - -#define LOG_MODULENAME "[metronom ] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - -#define XVDR_METRONOM_COMPILE -#include "xvdr_metronom.h" - - -static void got_video_frame(metronom_t *metronom, vo_frame_t *frame) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - this->video_frames++; - - if (this->frame_decoded) - this->frame_decoded(this->handle, this->video_frames, this->audio_frames); - - return this->orig_metronom->got_video_frame (this->orig_metronom, frame); -} - -static int64_t got_audio_samples(metronom_t *metronom, int64_t pts, int nsamples) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - this->audio_frames++; - - if (this->frame_decoded) - this->frame_decoded(this->handle, this->video_frames, this->audio_frames); - - return this->orig_metronom->got_audio_samples (this->orig_metronom, pts, nsamples); -} - -/* - * dummy hooks - */ - -static int64_t got_spu_packet(metronom_t *metronom, int64_t pts) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - return this->orig_metronom->got_spu_packet(this->orig_metronom, pts); -} - -static void handle_audio_discontinuity(metronom_t *metronom, int type, int64_t disc_off) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->handle_audio_discontinuity(this->orig_metronom, type, disc_off); -} - -static void handle_video_discontinuity(metronom_t *metronom, int type, int64_t disc_off) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->handle_video_discontinuity(this->orig_metronom, type, disc_off); -} - -static void set_audio_rate(metronom_t *metronom, int64_t pts_per_smpls) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_audio_rate(this->orig_metronom, pts_per_smpls); -} - -static void set_option(metronom_t *metronom, int option, int64_t value) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_option(this->orig_metronom, option, value); -} - -static int64_t get_option(metronom_t *metronom, int option) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - return this->orig_metronom->get_option(this->orig_metronom, option); -} - -static void set_master(metronom_t *metronom, metronom_t *master) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_master(this->orig_metronom, master); -} - -static void metronom_exit(metronom_t *metronom) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - LOGERR("xvdr_metronom: metronom_exit() called !"); - - /* un-hook */ - this->stream->metronom = this->orig_metronom; - this->orig_metronom = NULL; - this->stream = NULL; - - this->orig_metronom->exit(this->orig_metronom); -} - -/* - * xvdr_metronom_t - */ - -static void xvdr_metronom_set_cb(xvdr_metronom_t *this, - void (*cb)(void*, uint, uint), - void *handle) -{ - this->handle = handle; - this->frame_decoded = cb; -} - -static void xvdr_metronom_dispose(xvdr_metronom_t *this) -{ - if (this->stream && this->orig_metronom) - this->stream->metronom = this->orig_metronom; - - free(this); -} - -static void xvdr_metronom_reset_frames(xvdr_metronom_t *this) -{ - this->video_frames = this->audio_frames = 0; -} - -/* - * init - */ - -xvdr_metronom_t *xvdr_metronom_init(xine_stream_t *stream) -{ - xvdr_metronom_t *this = calloc(1, sizeof(xvdr_metronom_t)); - - this->stream = stream; - this->orig_metronom = stream->metronom; - - this->set_cb = xvdr_metronom_set_cb; - this->reset_frames = xvdr_metronom_reset_frames; - this->dispose = xvdr_metronom_dispose; - - this->metronom.set_audio_rate = set_audio_rate; - this->metronom.got_video_frame = got_video_frame; - this->metronom.got_audio_samples = got_audio_samples; - this->metronom.got_spu_packet = got_spu_packet; - this->metronom.handle_audio_discontinuity = handle_audio_discontinuity; - this->metronom.handle_video_discontinuity = handle_video_discontinuity; - this->metronom.set_option = set_option; - this->metronom.get_option = get_option; - this->metronom.set_master = set_master; - - this->metronom.exit = metronom_exit; - - /* hook up to stream */ - this->stream->metronom = &this->metronom; - - return this; -} diff --git a/xine/xvdr_metronom.h b/xine/xvdr_metronom.h deleted file mode 100644 index 21188f28..00000000 --- a/xine/xvdr_metronom.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * xvdr_metronom.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xvdr_metronom.h,v 1.1 2009-05-22 21:02:30 phintuka Exp $ - * - */ - -#ifndef XVDR_METRONOM_H -#define XVDR_METRONOM_H - -typedef struct xvdr_metronom_s xvdr_metronom_t; - -struct xvdr_metronom_s { - /* xine-lib metronom interface */ - metronom_t metronom; - - /* management interface */ - void (*set_cb) (xvdr_metronom_t *, - void (*cb) (void *, uint, uint), - void *); - void (*reset_frames)(xvdr_metronom_t *); - void (*dispose) (xvdr_metronom_t *); - - /* accumulated frame data */ - volatile uint video_frames; - volatile uint audio_frames; - - /* private data */ - -#ifdef XVDR_METRONOM_COMPILE - - /* original metronom */ - metronom_t *orig_metronom; - xine_stream_t *stream; - - /* callback */ - void *handle; - void (*frame_decoded)(void *handle, uint video_count, uint audio_count); - -#endif -}; - -xvdr_metronom_t *xvdr_metronom_init(xine_stream_t *); - - -#endif /* XVDR_METRONOM_H */ |