summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_out/audio_file_out.c16
-rw-r--r--src/audio_out/audio_jack_out.c5
-rw-r--r--src/audio_out/audio_pulse_out.c3
-rw-r--r--src/demuxers/demux_asf.c18
-rw-r--r--src/demuxers/demux_avi.c4
-rw-r--r--src/demuxers/demux_iff.c2
-rw-r--r--src/demuxers/demux_matroska.c6
-rw-r--r--src/demuxers/demux_mpeg_block.c4
-rw-r--r--src/demuxers/demux_mpeg_pes.c5
-rw-r--r--src/demuxers/demux_ogg.c31
-rw-r--r--src/demuxers/demux_real.c4
-rw-r--r--src/demuxers/demux_ts.c483
-rw-r--r--src/demuxers/demux_wc3movie.c3
-rw-r--r--src/input/Makefile.am10
-rw-r--r--src/input/input_bluray.c1744
-rw-r--r--src/input/input_net.c15
-rw-r--r--src/input/net_buf_ctrl.c4
-rw-r--r--src/libspudvb/xine_spudvb_decoder.c65
-rw-r--r--src/libspuhdmv/xine_hdmv_decoder.c2
-rw-r--r--src/libsputext/xine_sputext_decoder.c2
-rw-r--r--src/post/audio/stretch.c2
-rw-r--r--src/post/audio/upmix_mono.c2
-rw-r--r--src/post/deinterlace/xine_plugin.c3
-rw-r--r--src/video_out/video_out_fb.c2
-rw-r--r--src/video_out/video_out_opengl.c8
-rw-r--r--src/video_out/video_out_raw.c2
-rw-r--r--src/video_out/video_out_xcbshm.c2
-rw-r--r--src/video_out/video_out_xcbxv.c8
-rw-r--r--src/video_out/video_out_xvmc.c2
-rw-r--r--src/xine-engine/buffer.h2
-rw-r--r--src/xine-utils/memcpy.c19
31 files changed, 2238 insertions, 240 deletions
diff --git a/src/audio_out/audio_file_out.c b/src/audio_out/audio_file_out.c
index 802461e0e..bc40d4efd 100644
--- a/src/audio_out/audio_file_out.c
+++ b/src/audio_out/audio_file_out.c
@@ -274,10 +274,20 @@ static void ao_file_close(ao_driver_t *this_gen)
this->fname, this->bytes_written / 1024);
if (lseek(this->fd, 40, SEEK_SET) != -1) {
- write(this->fd, &len, 4);
+ if (write(this->fd, &len, 4) != 4) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_file_out: Failed to write header to file '%s': %s\n",
+ this->fname, strerror(errno));
+ }
+
len = le2me_32(this->bytes_written + 0x24);
- if (lseek(this->fd, 4, SEEK_SET) != -1)
- write(this->fd, &len, 4);
+ if (lseek(this->fd, 4, SEEK_SET) != -1) {
+ if (write(this->fd, &len, 4) != 4) {
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "audio_file_out: Failed to write header to file '%s': %s\n",
+ this->fname, strerror(errno));
+ }
+ }
+
}
close(this->fd);
diff --git a/src/audio_out/audio_jack_out.c b/src/audio_out/audio_jack_out.c
index a343310f0..1fadb3a13 100644
--- a/src/audio_out/audio_jack_out.c
+++ b/src/audio_out/audio_jack_out.c
@@ -278,12 +278,13 @@ static int jack_callback (jack_nframes_t nframes, void *arg)
return 0;
}
-
+#if 0
static void jack_shutdown (void *arg)
{
jack_driver_t *this = (jack_driver_t *) arg;
this->client = NULL;
}
+#endif
/*
* Open the Jack audio device
@@ -295,7 +296,6 @@ static int jack_open_device (ao_driver_t *this_gen, char *jack_device,
{
jack_driver_t *this = (jack_driver_t *) this_gen;
const char **matching_ports = NULL;
- char *port_name = NULL;
jack_client_t *client = this->client;
int port_flags = JackPortIsInput;
@@ -686,7 +686,6 @@ static ao_driver_t *open_jack_plugin (audio_driver_class_t *class_gen,
uint32_t rate;
char *jack_device;
const char **matching_ports = NULL;
- const char **port_names;
/* for usability reasons, keep this in sync with audio_oss_out.c */
static char *speaker_arrangement[] = {
diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c
index ae74a57bc..93e134785 100644
--- a/src/audio_out/audio_pulse_out.c
+++ b/src/audio_out/audio_pulse_out.c
@@ -360,7 +360,6 @@ static int ao_pulse_open(ao_driver_t *this_gen,
pulse_driver_t *this = (pulse_driver_t *) this_gen;
pa_sample_spec ss;
pa_channel_map cm;
- int r;
xprintf (this->xine, XINE_VERBOSITY_DEBUG,
"audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode);
@@ -466,7 +465,7 @@ static int ao_pulse_open(ao_driver_t *this_gen,
pa_stream_set_write_callback(this->stream, __xine_pa_stream_request_callback, this);
pa_stream_set_latency_update_callback(this->stream, __xine_pa_stream_notify_callback, this);
- r = pa_stream_connect_playback(this->stream, this->sink, NULL,
+ pa_stream_connect_playback(this->stream, this->sink, NULL,
PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE,
NULL, NULL);
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c
index 1250ba9a5..d2f0a89de 100644
--- a/src/demuxers/demux_asf.c
+++ b/src/demuxers/demux_asf.c
@@ -513,13 +513,13 @@ static int asf_read_header (demux_asf_t *this) {
* XX bytes : optional palette
*/
uint32_t width, height;
- uint16_t bmiheader_size;
+ /*uint16_t bmiheader_size;*/
xine_bmiheader *bmiheader;
width = _X_LE_32(asf_stream->private_data);
height = _X_LE_32(asf_stream->private_data + 4);
/* there is one unknown byte between height and the bmiheader size */
- bmiheader_size = _X_LE_16(asf_stream->private_data + 9);
+ /*bmiheader_size = _X_LE_16(asf_stream->private_data + 9);*/
/* FIXME: bmiheader_size must be >= sizeof(xine_bmiheader) */
@@ -998,8 +998,10 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) {
/* return 0 if ok */
static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_size) {
+#ifdef LOG
int64_t timestamp;
int64_t duration;
+#endif
this->packet_len_flags = get_byte(this); p_hdr_size += 1;
this->packet_prop_flags = get_byte(this); p_hdr_size += 1;
@@ -1038,8 +1040,10 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz
this->packet_padsize = 0;
}
+#ifdef LOG
timestamp = get_le32(this); p_hdr_size += 4;
duration = get_le16(this); p_hdr_size += 2;
+#endif
lprintf ("timestamp=%"PRId64", duration=%"PRId64"\n", timestamp, duration);
@@ -1581,11 +1585,11 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) {
ENTRYREF, MOREINFO, PARAM, REPEAT, TITLE
*/
- const char *base_href = NULL;
+ /*const char *base_href = NULL;*/
for (asx_entry = xml_tree->child; asx_entry; asx_entry = asx_entry->next)
{
- const char *ref_base_href = base_href;
+ /*const char *ref_base_href = base_href;*/
if (!strcasecmp (asx_entry->name, "ENTRY"))
{
@@ -1641,9 +1645,11 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) {
duration = asx_get_time_value (asx_ref);
}
+#if 0
else if (!strcasecmp (asx_ref->name, "BASE"))
/* Attributes: HREF */
- ref_base_href = xml_parser_get_property (asx_entry, "HREF");
+ ref_base_href = xml_parser_get_property (asx_entry, "HREF");
+#endif
}
/* FIXME: prepend ref_base_href to href */
@@ -1661,9 +1667,11 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) {
_x_demux_send_mrl_reference (this->stream, 0, href, NULL, 0, -1);
}
+#if 0
else if (!strcasecmp (asx_entry->name, "BASE"))
/* Attributes: HREF */
base_href = xml_parser_get_property (asx_entry, "HREF");
+#endif
}
}
else
diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c
index 02c242137..79bfc9f12 100644
--- a/src/demuxers/demux_avi.c
+++ b/src/demuxers/demux_avi.c
@@ -732,8 +732,6 @@ static avi_t *XINE_MALLOC AVI_init(demux_avi_t *this) {
int lasttag = 0;
int vids_strh_seen = 0;
int vids_strf_seen = 0;
- int auds_strh_seen = 0;
- int auds_strf_seen = 0;
int num_stream = 0;
uint8_t data[256];
int strf_size;
@@ -898,7 +896,6 @@ static avi_t *XINE_MALLOC AVI_init(demux_avi_t *this) {
a->dwSampleSize = _X_LE_32(hdrl_data + i + 44);
a->audio_tot = 0;
- auds_strh_seen = 1;
lprintf("audio stream header, num_stream=%d\n", num_stream);
lasttag = 2; /* auds */
@@ -985,7 +982,6 @@ static avi_t *XINE_MALLOC AVI_init(demux_avi_t *this) {
AVI->audio[AVI->n_audio-1]->wavex = wavex;
AVI->audio[AVI->n_audio-1]->wavex_len = n;
lprintf("audio stream format\n");
- auds_strf_seen = 1;
}
} else if(strncasecmp(hdrl_data + i, "indx",4) == 0) {
diff --git a/src/demuxers/demux_iff.c b/src/demuxers/demux_iff.c
index 1785e86d7..fb7d1c748 100644
--- a/src/demuxers/demux_iff.c
+++ b/src/demuxers/demux_iff.c
@@ -689,7 +689,6 @@ static int demux_iff_send_chunk(demux_plugin_t *this_gen) {
int64_t zw_pts;
int64_t zw_rescale;
int j, k;
- int first_buf;
int interleave_index;
int size;
@@ -791,7 +790,6 @@ static int demux_iff_send_chunk(demux_plugin_t *this_gen) {
interleave_index = (current_file_pos *
this->audio_compression_factor);
}
- first_buf = 1;
zw_pts = current_file_pos;
diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c
index ff2658a0c..242293502 100644
--- a/src/demuxers/demux_matroska.c
+++ b/src/demuxers/demux_matroska.c
@@ -1846,7 +1846,7 @@ static int parse_block (demux_matroska_t *this, size_t block_size,
uint64_t track_num;
uint8_t *data;
uint8_t flags;
- int gap, lacing, num_len;
+ int lacing, num_len;
int16_t timecode_diff;
int64_t pts, xduration;
int decoder_flags = 0;
@@ -1866,7 +1866,7 @@ static int parse_block (demux_matroska_t *this, size_t block_size,
lprintf("track_num: %" PRIu64 ", timecode_diff: %d, flags: 0x%x\n", track_num, timecode_diff, flags);
- gap = flags & 1;
+ /*gap = flags & 1;*/
lacing = (flags >> 1) & 0x3;
/*fprintf(stderr, "lacing: %x\n", lacing);*/
@@ -2077,7 +2077,6 @@ static int parse_block (demux_matroska_t *this, size_t block_size,
static int parse_simpleblock(demux_matroska_t *this, size_t block_len, uint64_t cluster_timecode, uint64_t block_duration)
{
- int has_block = 0;
off_t block_pos = 0;
off_t file_len = 0;
int normpos = 0;
@@ -2092,7 +2091,6 @@ static int parse_simpleblock(demux_matroska_t *this, size_t block_len, uint64_t
if (!read_block_data(this, block_len, this->compress_maxlen))
return 0;
- has_block = 1;
/* we have the duration, we can parse the block now */
if (!parse_block(this, block_len, cluster_timecode, block_duration,
normpos, is_key))
diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c
index aa5294e8b..08655ada9 100644
--- a/src/demuxers/demux_mpeg_block.c
+++ b/src/demuxers/demux_mpeg_block.c
@@ -868,6 +868,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_
} else if ((p[0]&0xf0) == 0xa0) {
int pcm_offset;
+#if 0
int number_of_frame_headers;
int first_access_unit_pointer;
int audio_frame_number;
@@ -875,6 +876,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_
int sample_rate;
int num_channels;
int dynamic_range;
+#endif
/*
* found in http://members.freemail.absa.co.za/ginggs/dvd/mpeg2_lpcm.txt
@@ -882,6 +884,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_
*/
track = p[0] & 0x0F;
+#if 0
number_of_frame_headers = p[1];
/* unknown = p[2]; */
first_access_unit_pointer = p[3];
@@ -906,6 +909,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_
case 2: bits_per_sample = 24; break;
}
dynamic_range = p[6];
+#endif
/* send lpcm config byte */
buf->decoder_flags |= BUF_FLAG_SPECIAL;
diff --git a/src/demuxers/demux_mpeg_pes.c b/src/demuxers/demux_mpeg_pes.c
index 9ef7221f0..305069b3c 100644
--- a/src/demuxers/demux_mpeg_pes.c
+++ b/src/demuxers/demux_mpeg_pes.c
@@ -975,6 +975,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el
} else if ((p[0]&0xf0) == 0xa0) {
int pcm_offset;
+#if 0
int number_of_frame_headers;
int first_access_unit_pointer;
int audio_frame_number;
@@ -982,13 +983,14 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el
int sample_rate;
int num_channels;
int dynamic_range;
-
+#endif
/*
* found in http://members.freemail.absa.co.za/ginggs/dvd/mpeg2_lpcm.txt
* appears to be correct.
*/
track = p[0] & 0x0F;
+#if 0
number_of_frame_headers = p[1];
/* unknown = p[2]; */
first_access_unit_pointer = p[3];
@@ -1019,6 +1021,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el
case 2: bits_per_sample = 24; break;
}
dynamic_range = p[6];
+#endif
/* send lpcm config byte */
buf->decoder_flags |= BUF_FLAG_SPECIAL;
diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c
index e0abd0cd6..8849e445e 100644
--- a/src/demuxers/demux_ogg.c
+++ b/src/demuxers/demux_ogg.c
@@ -931,21 +931,27 @@ static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_pa
xine_bmiheader bih;
int channel;
+#ifdef LOG
int16_t locbits_per_sample;
+ int32_t locsize, locdefault_len, locbuffersize;
+ int64_t locsamples_per_unit;
+#endif
uint32_t locsubtype;
- int32_t locsize, locdefault_len, locbuffersize, locwidth, locheight;
- int64_t loctime_unit, locsamples_per_unit;
+ int32_t locwidth, locheight;
+ int64_t loctime_unit;
/* read fourcc with machine endianness */
locsubtype = *((uint32_t *)&op->packet[9]);
/* everything else little endian */
- locsize = _X_LE_32(&op->packet[13]);
loctime_unit = _X_LE_64(&op->packet[17]);
+#ifdef LOG
+ locsize = _X_LE_32(&op->packet[13]);
locsamples_per_unit = _X_LE_64(&op->packet[25]);
locdefault_len = _X_LE_32(&op->packet[33]);
locbuffersize = _X_LE_32(&op->packet[37]);
locbits_per_sample = _X_LE_16(&op->packet[41]);
+#endif
locwidth = _X_LE_32(&op->packet[45]);
locheight = _X_LE_32(&op->packet[49]);
@@ -1014,18 +1020,25 @@ static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_pa
char str[5];
int channel;
- int16_t locbits_per_sample, locchannels, locblockalign;
- int32_t locsize, locdefault_len, locbuffersize, locavgbytespersec;
- int64_t loctime_unit, locsamples_per_unit;
+#ifdef LOG
+ int16_t locblockalign;
+ int32_t locsize, locdefault_len, locbuffersize;
+ int64_t loctime_unit;
+#endif
+ int16_t locbits_per_sample, locchannels;
+ int32_t locavgbytespersec;
+ int64_t locsamples_per_unit;
+#ifdef LOG
locsize = _X_LE_32(&op->packet[13]);
loctime_unit = _X_LE_64(&op->packet[17]);
- locsamples_per_unit = _X_LE_64(&op->packet[25]);
- locdefault_len = _X_LE_32(&op->packet[33]);
locbuffersize = _X_LE_32(&op->packet[37]);
+ locdefault_len = _X_LE_32(&op->packet[33]);
+ locblockalign = _X_LE_16(&op->packet[47]);
+#endif
+ locsamples_per_unit = _X_LE_64(&op->packet[25]);
locbits_per_sample = _X_LE_16(&op->packet[41]);
locchannels = _X_LE_16(&op->packet[45]);
- locblockalign = _X_LE_16(&op->packet[47]);
locavgbytespersec= _X_LE_32(&op->packet[49]);
lprintf ("direct show filter created audio stream detected, hexdump:\n");
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c
index 19b7794ef..9ecf6b622 100644
--- a/src/demuxers/demux_real.c
+++ b/src/demuxers/demux_real.c
@@ -546,7 +546,7 @@ static void real_parse_headers (demux_real_t *this) {
lprintf("audio version %d detected\n", version);
- char *fourcc_ptr = "\0\0\0";
+ const char *fourcc_ptr = "\0\0\0";
switch(version) {
case 3:
/* Version 3 header stores fourcc after meta info - cheat by reading backwards from the
@@ -1251,7 +1251,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) {
buf->size = 0;
buf->type = this->video_stream->buf_type;
- xine_fast_memcpy(buf->decoder_info_ptr[2], this->fragment_tab,
+ xine_fast_memcpy(buf->content, this->fragment_tab,
this->fragment_count*8);
this->video_fifo->put(this->video_fifo, buf);
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c
index ef71bdfa5..88ccf49f4 100644
--- a/src/demuxers/demux_ts.c
+++ b/src/demuxers/demux_ts.c
@@ -182,8 +182,6 @@
#define BUF_SIZE (NPKT_PER_READ * (PKT_SIZE + 4))
-#define MAX_PES_BUF_SIZE 2048
-
#define CORRUPT_PES_THRESHOLD 10
#define NULL_PID 0x1fff
@@ -250,6 +248,10 @@
HDMV_SPU_INTERACTIVE = 0x91,
HDMV_SPU_TEXT = 0x92,
+ /* pseudo tags */
+ STREAM_AUDIO_EAC3 = (DESCRIPTOR_EAC3 << 8),
+ STREAM_AUDIO_DTS = (DESCRIPTOR_DTS << 8),
+
} streamType;
#define WRAP_THRESHOLD 270000
@@ -285,13 +287,14 @@
typedef struct {
unsigned int pid;
fifo_buffer_t *fifo;
- 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?) */
+ uint8_t keep; /* used by demux_ts_dynamic_pmt_*() */
int corrupted_pes;
+ int pes_bytes_left; /* butes left if PES packet size is known */
int input_normpos;
int input_time;
@@ -329,6 +332,7 @@ typedef struct {
fifo_buffer_t *video_fifo;
input_plugin_t *input;
+ unsigned int read_retries;
int status;
@@ -408,6 +412,169 @@ typedef struct {
config_values_t *config;
} demux_ts_class_t;
+static void reset_track_map(fifo_buffer_t *fifo)
+{
+ buf_element_t *buf = fifo->buffer_pool_alloc (fifo);
+
+ buf->type = BUF_CONTROL_RESET_TRACK_MAP;
+ buf->decoder_info[1] = -1;
+
+ fifo->put (fifo, buf);
+}
+
+/* TJ. dynamic PMT support. The idea is:
+ First, reuse unchanged pids and add new ones.
+ Then, comb out those who are no longer referenced.
+ For example, the Kaffeine dvb frontend preserves original pids but only
+ sends the currently user selected ones, plus matching generated pat/pmt */
+
+static int demux_ts_dynamic_pmt_find (demux_ts_t *this,
+ int pid, int type, unsigned int descriptor_tag) {
+ unsigned int i;
+ demux_ts_media *m;
+ for (i = 0; i < this->media_num; i++) {
+ m = &this->media[i];
+ if ((m->pid == pid) && ((m->type & BUF_MAJOR_MASK) == type)) {
+ /* mark this media decriptor for reuse */
+ m->keep = 1;
+ return i;
+ }
+ }
+ if (i < MAX_PIDS) {
+ /* prepare new media descriptor */
+#ifdef LOG_DYNAMIC_PMT
+ char *name = "";
+ if (type == BUF_VIDEO_BASE) name = "video";
+ else if (type == BUF_AUDIO_BASE) name = "audio";
+ else if (type == BUF_SPU_BASE) name = "subtitle";
+ printf ("demux_ts: new %s pid %d\n", name, pid);
+#endif
+ m = &this->media[i];
+ if (type == BUF_AUDIO_BASE) {
+ /* allocate new audio track as well */
+ if (this->audio_tracks_count >= MAX_AUDIO_TRACKS) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "demux_ts: too many audio PIDs, ignoring pid %d\n", pid);
+ return -1;
+ }
+ m->type = type | this->audio_tracks_count;
+ this->audio_tracks[this->audio_tracks_count].pid = pid;
+ this->audio_tracks[this->audio_tracks_count].media_index = i;
+ this->audio_tracks_count++;
+ m->fifo = this->stream->audio_fifo;
+ } else {
+ m->type = type;
+ m->fifo = this->stream->video_fifo;
+ }
+ m->pid = pid;
+
+ if (m->buf) {
+ m->buf->free_buffer(m->buf);
+ m->buf = NULL;
+ }
+ m->counter = INVALID_CC;
+ m->corrupted_pes = 1;
+ m->pts = 0;
+
+ m->descriptor_tag = descriptor_tag;
+
+ m->keep = 1;
+ this->media_num++;
+ return i;
+ }
+ /* table full */
+ return -1;
+}
+
+static void demux_ts_dynamic_pmt_clean (demux_ts_t *this) {
+ int i, count = 0, tracks = 0, spus = 0;
+ /* densify media table */
+ for (i = 0; i < this->media_num; i++) {
+ demux_ts_media *m = &this->media[i];
+ int type = m->type & BUF_MAJOR_MASK;
+ int chan = m->type & 0xff;
+ if (m->keep) {
+ m->keep = 0;
+ if (type == BUF_VIDEO_BASE) {
+ /* adjust single video link */
+ this->videoMedia = count;
+ } else if (type == BUF_AUDIO_BASE) {
+ /* densify audio track table */
+ this->audio_tracks[chan].media_index = count;
+ if (chan > tracks) {
+ m->type = (m->type & ~0xff) | tracks;
+ this->audio_tracks[tracks] = this->audio_tracks[chan];
+ }
+ tracks++;
+ } else if (type == BUF_SPU_BASE) {
+ /* spu language table has already been rebuilt from scratch.
+ Adjust backlinks only */
+ while ((spus < this->spu_langs_count) && (this->spu_langs[spus].pid == m->pid)) {
+ this->spu_langs[spus].media_index = count;
+ spus++;
+ }
+ }
+ if (i > count) {
+ this->media[count] = *m;
+ m->buf = NULL;
+ m->pid = INVALID_PID;
+ }
+ count++;
+ } else {
+ /* drop this no longer needed media descriptor */
+#ifdef LOG_DYNAMIC_PMT
+ char *name = "";
+ if (type == BUF_VIDEO_BASE) name = "video";
+ else if (type == BUF_AUDIO_BASE) name = "audio";
+ else if (type == BUF_SPU_BASE) name = "subtitle";
+ printf ("demux_ts: dropped %s pid %d\n", name, m->pid);
+#endif
+ if (m->buf) {
+ m->buf->free_buffer (m->buf);
+ m->buf = NULL;
+ }
+ m->pid = INVALID_PID;
+ }
+ }
+ if ((tracks < this->audio_tracks_count) && this->audio_fifo) {
+ /* at least 1 audio track removed, tell audio decoder loop */
+ reset_track_map(this->audio_fifo);
+#ifdef LOG_DYNAMIC_PMT
+ printf ("demux_ts: new audio track map\n");
+#endif
+ }
+#ifdef LOG_DYNAMIC_PMT
+ printf ("demux_ts: using %d pids, %d audio %d subtitle channels\n", count, tracks, spus);
+#endif
+ /* adjust table sizes */
+ this->media_num = count;
+ this->audio_tracks_count = tracks;
+ /* should really have no effect */
+ this->spu_langs_count = spus;
+}
+
+static void demux_ts_dynamic_pmt_clear (demux_ts_t *this) {
+ unsigned int i;
+ for (i = 0; i < this->media_num; i++) {
+ if (this->media[i].buf) {
+ this->media[i].buf->free_buffer (this->media[i].buf);
+ this->media[i].buf = NULL;
+ }
+ }
+ this->media_num = 0;
+
+ this->videoPid = INVALID_PID;
+ this->audio_tracks_count = 0;
+ this->spu_pid = INVALID_PID;
+ this->spu_langs_count = 0;
+ this->spu_media = 0;
+
+ this->pcr_pid = INVALID_PID;
+
+ this->last_pmt_crc = 0;
+}
+
+
static void demux_ts_tbre_reset (demux_ts_t *this) {
if (this->tbre_time <= TBRE_TIME) {
this->tbre_pid = INVALID_PID;
@@ -576,6 +743,9 @@ static void demux_ts_update_spu_channel(demux_ts_t *this)
this->spu_pid = lang->pid;
this->spu_media = lang->media_index;
+ /* multiple spu langs can share same media descriptor */
+ this->media[lang->media_index].type =
+ (this->media[lang->media_index].type & ~0xff) | this->current_spu_channel;
#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);
@@ -630,6 +800,7 @@ static void demux_ts_flush(demux_ts_t *this)
unsigned int i;
for (i = 0; i < this->media_num; ++i) {
demux_ts_flush_media(&this->media[i]);
+ this->media[i].corrupted_pes = 1;
}
}
@@ -645,11 +816,13 @@ static void demux_ts_flush(demux_ts_t *this)
*/
static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt,
unsigned char *pkt, unsigned int pusi) {
+#ifdef TS_PAT_LOG
uint32_t table_id;
+ uint32_t version_number;
+#endif
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;
@@ -680,11 +853,15 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt,
"demux_ts: demux error! PAT with invalid pointer\n");
return;
}
+#ifdef TS_PAT_LOG
table_id = (unsigned int)pkt[5] ;
+#endif
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];
+#ifdef TS_PAT_LOG
version_number = ((uint32_t)pkt[10] >> 1) & 0x1f;
+#endif
current_next_indicator = ((uint32_t)pkt[10] & 0x01);
section_number = (uint32_t)pkt[11];
last_section_number = (uint32_t)pkt[12];
@@ -779,11 +956,7 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt,
/* force PMT reparsing when pmt_pid changes */
if (this->pmt_pid[program_count] != pmt_pid) {
this->pmt_pid[program_count] = pmt_pid;
- this->audio_tracks_count = 0;
- this->last_pmt_crc = 0;
- this->videoPid = INVALID_PID;
- this->spu_pid = INVALID_PID;
- this->pcr_pid = INVALID_PID;
+ demux_ts_dynamic_pmt_clear (this);
if (this->pmt[program_count] != NULL) {
free(this->pmt[program_count]);
@@ -834,14 +1007,13 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
return 0 ;
}
- /* packet_len = p[4] << 8 | p[5]; */
stream_id = p[3];
- header_len = p[8];
+ header_len = p[8] + 9;
/* sometimes corruption on header_len causes segfault in memcpy below */
- if (header_len + 9 > packet_len) {
+ if (header_len > packet_len) {
xprintf (xine, XINE_VERBOSITY_DEBUG,
- "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len);
+ "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len - 9);
return 0;
}
@@ -852,7 +1024,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
if (p[7] & 0x80) { /* pts avail */
- if (header_len < 5) {
+ if (header_len < 14) {
return 0;
}
@@ -880,22 +1052,21 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
m->pts = pts;
- p += header_len + 9;
- packet_len -= header_len + 9;
+ m->pes_bytes_left = (int)(p[4] << 8 | p[5]) - header_len + 6;
+ lprintf("PES packet payload left: %d bytes\n", m->pes_bytes_left);
+
+ p += header_len;
+ packet_len -= header_len;
if (m->descriptor_tag == STREAM_VIDEO_VC1) {
- m->size = packet_len;
m->type = BUF_VIDEO_VC1;
- return 1;
+ return header_len;
}
if (m->descriptor_tag == HDMV_SPU_BITMAP) {
- long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3;
-
- m->size = packet_len;
m->type |= BUF_SPU_HDMV;
- m->buf->decoder_info[2] = payload_len;
- return 1;
+ m->buf->decoder_info[2] = m->pes_bytes_left;
+ return header_len;
} else
@@ -912,27 +1083,25 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
* these "raw" streams may begin with a byte that looks like a stream type.
* For audio streams, m->type already contains the stream no.
*/
- if(m->descriptor_tag == HDMV_AUDIO_84_EAC3) {
- m->size = packet_len;
+ if(m->descriptor_tag == HDMV_AUDIO_84_EAC3 ||
+ m->descriptor_tag == STREAM_AUDIO_EAC3) {
m->type |= BUF_AUDIO_EAC3;
- return 1;
+ return header_len;
} else if(m->descriptor_tag == STREAM_AUDIO_AC3) { /* ac3 - raw */
- m->size = packet_len;
m->type |= BUF_AUDIO_A52;
- return 1;
+ return header_len;
} else if (m->descriptor_tag == HDMV_AUDIO_83_TRUEHD) {
/* TODO: separate AC3 and TrueHD streams ... */
- m->size = packet_len;
m->type |= BUF_AUDIO_A52;
- return 1;
+ return header_len;
- } else if (m->descriptor_tag == HDMV_AUDIO_82_DTS ||
+ } else if (m->descriptor_tag == STREAM_AUDIO_DTS ||
+ m->descriptor_tag == HDMV_AUDIO_82_DTS ||
m->descriptor_tag == HDMV_AUDIO_86_DTS_HD_MA ) {
- m->size = packet_len;
m->type |= BUF_AUDIO_DTS;
- return 1;
+ return header_len;
} else if (packet_len < 2) {
return 0;
@@ -943,45 +1112,42 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
return 0;
}
- m->size = packet_len - 4;
m->type |= BUF_AUDIO_LPCM_BE;
m->buf->decoder_flags |= BUF_FLAG_SPECIAL;
m->buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG;
m->buf->decoder_info[2] = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
- return 1;
+ m->pes_bytes_left -= 4;
+ return header_len + 4;
} 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->size = packet_len;
m->type |= BUF_SPU_DVB;
- m->buf->decoder_info[2] = payload_len;
- return 1;
+ m->buf->decoder_info[2] = m->pes_bytes_left;
+ return header_len;
} else if (p[0] == 0x0B && p[1] == 0x77) { /* ac3 - syncword */
- m->size = packet_len;
m->type |= BUF_AUDIO_A52;
- return 1;
+ return header_len;
} else if ((p[0] & 0xE0) == 0x20) {
spu_id = (p[0] & 0x1f);
- m->size = packet_len-1;
m->type = BUF_SPU_DVD + spu_id;
- return 1;
+ m->pes_bytes_left -= 1;
+ return header_len + 1;
+
} else if ((p[0] & 0xF0) == 0x80) {
if (packet_len < 4) {
return 0;
}
- m->size = packet_len - 4;
m->type |= BUF_AUDIO_A52;
- return 1;
+ m->pes_bytes_left -= 4;
+ return header_len + 4;
#if 0
/* commented out: does not set PCM type. Decoder can't handle raw PCM stream without configuration. */
@@ -1000,15 +1166,14 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
return 0;
}
- m->size = packet_len-pcm_offset;
m->type |= BUF_AUDIO_LPCM_BE;
- return 1;
+ m->pes_bytes_left -= pcm_offset;
+ return header_len + pcm_offset;
#endif
}
} else if ((stream_id & 0xf0) == 0xe0) {
- m->size = packet_len;
switch (m->descriptor_tag) {
case ISO_11172_VIDEO:
case ISO_13818_VIDEO:
@@ -1029,11 +1194,10 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
m->type = BUF_VIDEO_MPEG;
break;
}
- return 1;
+ return header_len;
} else if ((stream_id & 0xe0) == 0xc0) {
- m->size = packet_len;
switch (m->descriptor_tag) {
case ISO_11172_AUDIO:
case ISO_13818_AUDIO:
@@ -1053,7 +1217,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m,
m->type |= BUF_AUDIO_MPEG;
break;
}
- return 1;
+ return header_len;
} else {
#ifdef TS_LOG
@@ -1114,7 +1278,9 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts,
/* 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)) {
+ int pes_header_len = demux_ts_parse_pes_header(this->stream->xine, m, ts, len);
+
+ if (pes_header_len <= 0) {
m->buf->free_buffer(m->buf);
m->buf = NULL;
@@ -1124,8 +1290,10 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts,
} else {
m->corrupted_pes = 0;
- memcpy(m->buf->mem, ts+len-m->size, m->size);
- m->buf->size = m->size;
+
+ /* skip PES header */
+ ts += pes_header_len;
+ len -= pes_header_len;
update_extra_info(this, m);
@@ -1135,41 +1303,29 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts,
if (m->pid == this->tbre_pid)
demux_ts_tbre_update (this, TBRE_MODE_AUDIO_PTS, m->pts);
}
+ }
- } else if (!m->corrupted_pes) { /* no pus -- PES packet continuation */
+ if (!m->corrupted_pes) {
- if ((m->buf->size + len) > MAX_PES_BUF_SIZE) {
+ if ((m->buf->size + len) > m->buf->max_size) {
+ m->pes_bytes_left -= m->buf->size;
demux_ts_send_buffer(m, 0);
m->buf = m->fifo->buffer_pool_alloc(m->fifo);
}
+
memcpy(m->buf->mem + m->buf->size, ts, len);
m->buf->size += len;
- }
-}
-
-/*
- * Create a buffer for a PES stream.
- */
-static void demux_ts_pes_new(demux_ts_t*this,
- unsigned int mediaIndex,
- unsigned int pid,
- fifo_buffer_t *fifo,
- uint16_t descriptor) {
- demux_ts_media *m = &this->media[mediaIndex];
-
- /* new PID seen - initialise stuff */
- m->pid = pid;
- m->fifo = fifo;
-
- if (m->buf != NULL) m->buf->free_buffer(m->buf);
- m->buf = NULL;
- m->counter = INVALID_CC;
- m->descriptor_tag = descriptor;
- m->corrupted_pes = 1;
+ if (m->pes_bytes_left > 0 && m->buf->size >= m->pes_bytes_left) {
+ /* PES payload complete */
+ m->pes_bytes_left -= m->buf->size;
+ demux_ts_flush_media(m);
+ /* skip rest data - there shouldn't be any */
+ m->corrupted_pes = 1;
+ }
+ }
}
-
/* Find the first ISO 639 language descriptor (tag 10) and
* store the 3-char code in dest, nullterminated. If no
* code is found, zero out dest.
@@ -1260,11 +1416,13 @@ static void demux_ts_parse_pmt (demux_ts_t *this,
unsigned int pusi,
uint32_t program_count) {
+#ifdef TS_PMT_LOG
uint32_t table_id;
+ uint32_t version_number;
+#endif
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;
@@ -1279,6 +1437,7 @@ static void demux_ts_parse_pmt (demux_ts_t *this,
char *ptr = NULL;
unsigned char len;
unsigned int offset=0;
+ int mi;
/*
* A new section should start with the payload unit start
@@ -1293,11 +1452,15 @@ static void demux_ts_parse_pmt (demux_ts_t *this,
this->pmt[program_count] = (uint8_t *) calloc(4096, sizeof(unsigned char));
this->pmt_write_ptr[program_count] = this->pmt[program_count];
+#ifdef TS_PMT_LOG
table_id = pkt[5] ;
+#endif
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];
+#ifdef TS_PMT_LOG
version_number = (pkt[10] >> 1) & 0x1f;
+#endif
current_next_indicator = pkt[10] & 0x01;
section_number = pkt[11];
last_section_number = pkt[12];
@@ -1425,10 +1588,12 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
* 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;
+ this->spu_langs_count = 0;
+ reset_track_map(this->video_fifo);
+
/*
* ES definitions start here...we are going to learn upto one video
* PID and one audio PID.
@@ -1454,7 +1619,6 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
/*
* Extract the elementary streams.
*/
- this->spu_langs_count = 0;
while (section_length > 0) {
unsigned int stream_info_length;
@@ -1481,9 +1645,12 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
#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;
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_VIDEO_BASE, stream[0]);
+ if (mi >= 0) {
+ this->videoMedia = mi;
+ this->videoPid = pid;
+ }
}
break;
@@ -1492,18 +1659,17 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
case ISO_13818_PART7_AUDIO:
case ISO_14496_PART3_AUDIO:
if (this->audio_tracks_count < MAX_AUDIO_TRACKS) {
- if (apid_check(this, pid) < 0) {
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE, stream[0]);
+ if (mi >= 0) {
#ifdef TS_PMT_LOG
- printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
+ 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++;
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
}
+
}
break;
case ISO_13818_PRIVATE:
@@ -1522,28 +1688,23 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
break;
case ISO_13818_PES_PRIVATE:
for (i = 5; i < coded_length; i += stream[i+1] + 2) {
- if (((stream[i] == DESCRIPTOR_AC3) || (stream[i] == DESCRIPTOR_EAC3)) &&
- (this->audio_tracks_count < MAX_AUDIO_TRACKS)) {
- if (apid_check(this, pid) < 0) {
+
+ if ((stream[i] == DESCRIPTOR_AC3) || (stream[i] == DESCRIPTOR_EAC3) || (stream[i] == DESCRIPTOR_DTS)) {
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE,
+ stream[i] == DESCRIPTOR_AC3 ? STREAM_AUDIO_AC3 :
+ stream[i] == DESCRIPTOR_DTS ? STREAM_AUDIO_DTS :
+ STREAM_AUDIO_EAC3);
+ if (mi >= 0) {
#ifdef TS_PMT_LOG
printf ("demux_ts: PMT AC3 audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
#endif
- if (stream[i] == DESCRIPTOR_AC3)
- demux_ts_pes_new(this, this->media_num, pid,
- this->audio_fifo, STREAM_AUDIO_AC3);
- else
- demux_ts_pes_new(this, this->media_num, pid,
- this->audio_fifo, HDMV_AUDIO_84_EAC3);
-
- this->audio_tracks[this->audio_tracks_count].pid = pid;
- this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
- this->media[this->media_num].type = this->audio_tracks_count;
- demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang,
- stream + 5, stream_info_length);
- this->audio_tracks_count++;
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
break;
}
}
+
/* Teletext */
else if (stream[i] == DESCRIPTOR_TELETEXT)
{
@@ -1561,6 +1722,10 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
else if (stream[i] == DESCRIPTOR_DVBSUB)
{
int pos;
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_SPU_BASE, stream[0]);
+ if (mi < 0) break;
+
for (pos = i + 2;
pos + 8 <= i + 2 + stream[i + 1]
&& this->spu_langs_count < MAX_SPU_LANGS;
@@ -1578,9 +1743,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
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]);
+ lang->media_index = mi;
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",
@@ -1615,15 +1778,17 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
break;
}
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_SPU_BASE, stream[0]);
+ if (mi < 0) break;
+
+
demux_ts_spu_lang *lang = &this->spu_langs[this->spu_langs_count];
memset(lang->desc.lang, 0, sizeof(lang->desc.lang));
/*memcpy(lang->desc.lang, &stream[pos], 3);*/
/*lang->desc.lang[3] = 0;*/
lang->pid = pid;
- lang->media_index = this->media_num;
- this->media[this->media_num].type = this->spu_langs_count;
- demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]);
+ lang->media_index = mi;
demux_send_special_spu_buf( this, BUF_SPU_HDMV, this->spu_langs_count );
this->spu_langs_count++;
#ifdef TS_PMT_LOG
@@ -1642,43 +1807,43 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
* if is does, we tag this as an audio stream.
* FIXME: This will need expanding if we ever see a DTS or other media format here.
*/
- if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) {
- if (apid_check(this,pid) < 0) {
- uint32_t format_identifier=0;
- demux_ts_get_reg_desc(this, &format_identifier,
- stream + 5, stream_info_length);
- /* If no format identifier, assume A52 */
- if (( format_identifier == 0x41432d33) ||
- ( format_identifier == 0) ||
- ((format_identifier == 0x48444d56 || this->hdmv>0) && stream[0] == HDMV_AUDIO_80_PCM) /* BluRay PCM */) {
-
- demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo, stream[0]);
- this->audio_tracks[this->audio_tracks_count].pid = pid;
- this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
- this->media[this->media_num].type = this->audio_tracks_count;
- demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang,
- stream + 5, stream_info_length);
- this->audio_tracks_count++;
- break;
- }
+ if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) {
+
+ uint32_t format_identifier=0;
+ demux_ts_get_reg_desc(this, &format_identifier, stream + 5, stream_info_length);
+ /* If no format identifier, assume A52 */
+ if (( format_identifier == 0x41432d33) ||
+ ( format_identifier == 0) ||
+ ((format_identifier == 0x48444d56 || this->hdmv>0) && stream[0] == HDMV_AUDIO_80_PCM) /* BluRay PCM */) {
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE, stream[0]);
+ if (mi >= 0) {
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
+#ifdef TS_PMT_LOG
+ printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
+#endif
+ break;
+ }
}
- } else {
+ }
#ifdef TS_PMT_LOG
- printf ("demux_ts: PMT unknown stream_type: 0x%.2x pid: 0x%.4x\n",
- stream[0], pid);
+ 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");
+ 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;
}
+ demux_ts_dynamic_pmt_clean (this);
+
/*
* Get the current PCR PID.
*/
@@ -1812,8 +1977,19 @@ static unsigned char * demux_synchronise(demux_ts_t* this) {
this->frame_pos = this->input->get_current_pos (this->input);
read_length = this->input->read(this->input, this->buf,
- this->pkt_size * NPKT_PER_READ);
- if (read_length < 0 || read_length % this->pkt_size) {
+ this->pkt_size * NPKT_PER_READ);
+
+ if (read_length < 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "demux_ts: read returned %d\n", read_length);
+ if (this->read_retries > 2)
+ this->status = DEMUX_FINISHED;
+ this->read_retries++;
+ return NULL;
+ }
+ this->read_retries = 0;
+
+ if (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);
@@ -1832,6 +2008,7 @@ static unsigned char * demux_synchronise(demux_ts_t* this) {
*/
if (this->npkt_read == 0) {
+ demux_ts_flush(this);
xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: read 0 packets\n");
this->status = DEMUX_FINISHED;
return NULL;
@@ -1964,7 +2141,9 @@ static void demux_ts_parse_packet (demux_ts_t*this) {
unsigned int sync_byte;
unsigned int transport_error_indicator;
unsigned int payload_unit_start_indicator;
+#ifdef TS_HEADER_LOG
unsigned int transport_priority;
+#endif
unsigned int pid;
unsigned int transport_scrambling_control;
unsigned int adaptation_field_control;
@@ -1982,7 +2161,9 @@ static void demux_ts_parse_packet (demux_ts_t*this) {
sync_byte = originalPkt[0];
transport_error_indicator = (originalPkt[1] >> 7) & 0x01;
payload_unit_start_indicator = (originalPkt[1] >> 6) & 0x01;
+#ifdef TS_HEADER_LOG
transport_priority = (originalPkt[1] >> 5) & 0x01;
+#endif
pid = ((originalPkt[1] << 8) |
originalPkt[2]) & 0x1fff;
transport_scrambling_control = (originalPkt[3] >> 6) & 0x03;
@@ -2154,15 +2335,8 @@ static void demux_ts_event_handler (demux_ts_t *this) {
case XINE_EVENT_PIDS_CHANGE:
- this->videoPid = INVALID_PID;
- this->pcr_pid = INVALID_PID;
- this->audio_tracks_count = 0;
- this->media_num = 0;
+ demux_ts_dynamic_pmt_clear(this);
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;
@@ -2297,6 +2471,7 @@ static int demux_ts_seek (demux_plugin_t *this_gen,
m->buf = NULL;
m->counter = INVALID_CC;
m->corrupted_pes = 1;
+ m->pts = 0;
}
if( !playing ) {
diff --git a/src/demuxers/demux_wc3movie.c b/src/demuxers/demux_wc3movie.c
index 36cc4eabb..3b310e90c 100644
--- a/src/demuxers/demux_wc3movie.c
+++ b/src/demuxers/demux_wc3movie.c
@@ -141,7 +141,6 @@ static int demux_mve_send_chunk(demux_plugin_t *this_gen) {
demux_mve_t *this = (demux_mve_t *) this_gen;
buf_element_t *buf = NULL;
- int64_t text_pts = 0;
int64_t audio_pts = 0;
unsigned char preamble[PREAMBLE_SIZE];
unsigned int chunk_tag;
@@ -264,7 +263,7 @@ static int demux_mve_send_chunk(demux_plugin_t *this_gen) {
}
this->video_pts += WC3_PTS_INC;
} else if (chunk_tag == TEXT_TAG) {
- text_pts = this->video_pts - WC3_PTS_INC;
+ /*text_pts = this->video_pts - WC3_PTS_INC;*/
/* unhandled thus far */
this->input->seek(this->input, chunk_size, SEEK_CUR);
diff --git a/src/input/Makefile.am b/src/input/Makefile.am
index 10c4f15ec..9700f6f58 100644
--- a/src/input/Makefile.am
+++ b/src/input/Makefile.am
@@ -56,6 +56,10 @@ if DVB
in_dvb = xineplug_inp_dvb.la
endif
+if HAVE_LIBBLURAY
+in_bluray = xineplug_inp_bluray.la
+endif
+
AM_CFLAGS = -D_LARGEFILE64_SOURCE $(GNOME_VFS_CFLAGS) $(ALSA_CFLAGS) $(DVD_CFLAGS)
xineplug_LTLIBRARIES = \
@@ -75,6 +79,7 @@ xineplug_LTLIBRARIES = \
xineplug_inp_net.la \
$(in_pvr) \
$(in_dvb) \
+ $(in_bluray) \
xineplug_inp_cdda.la
@@ -163,6 +168,11 @@ xineplug_inp_pvr_la_LIBADD = $(XINE_LIB) $(PTHREAD_LIBS) $(LTLIBINTL)
xineplug_inp_pvr_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS)
xineplug_inp_pvr_la_LDFLAGS = $(xineplug_ldflags)
+xineplug_inp_bluray_la_SOURCES = input_bluray.c media_helper.c
+xineplug_inp_bluray_la_LIBADD = $(XINE_LIB) $(LIBBLURAY_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL)
+xineplug_inp_bluray_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) $(LIBBLURAY_CFLAGS)
+xineplug_inp_bluray_la_LDFLAGS = $(xineplug_ldflags)
+
xineinclude_HEADERS = input_plugin.h
noinst_HEADERS = net_buf_ctrl.h mms.h mmsh.h pnm.h media_helper.h http_helper.h
diff --git a/src/input/input_bluray.c b/src/input/input_bluray.c
new file mode 100644
index 000000000..a05307a4f
--- /dev/null
+++ b/src/input/input_bluray.c
@@ -0,0 +1,1744 @@
+/*
+ * Copyright (C) 2000-2011 the xine project
+ * Copyright (C) 2009-2011 Petri Hintukainen <phintuka@users.sourceforge.net>
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Input plugin for BluRay discs / images
+ *
+ * Requires libbluray 0.2.1 or later:
+ * http://www.videolan.org/developers/libbluray.html
+ * git://git.videolan.org/libbluray.git
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+/* libbluray */
+#include <libbluray/bluray.h>
+#include <libbluray/bluray-version.h>
+#include <libbluray/keys.h>
+#include <libbluray/overlay.h>
+#include <libbluray/meta_data.h>
+
+/* xine */
+
+#define LOG_MODULE "input_bluray"
+#define LOG_VERBOSE
+
+#define LOG
+
+#define LOGMSG(x...) xine_log (this->stream->xine, XINE_LOG_MSG, "input_bluray: " x);
+
+#define XINE_ENGINE_INTERNAL
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "input_plugin.h"
+#include "media_helper.h"
+
+/* */
+
+#ifndef MIN
+# define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
+# define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#define ALIGNED_UNIT_SIZE 6144
+#define PKT_SIZE 192
+#define TICKS_IN_MS 45
+
+#define MIN_TITLE_LENGTH 180
+
+/* */
+
+typedef struct {
+
+ input_class_t input_class;
+
+ xine_t *xine;
+
+ xine_mrl_t **xine_playlist;
+ int xine_playlist_size;
+
+ /* config */
+ char *mountpoint;
+ char *device;
+ char *language;
+ char *country;
+ int region;
+ int parental;
+} bluray_input_class_t;
+
+typedef struct {
+ input_plugin_t input_plugin;
+
+ bluray_input_class_t *class;
+
+ xine_stream_t *stream;
+ xine_event_queue_t *event_queue;
+ xine_osd_t *osd[2];
+
+ char *mrl;
+ char *disc_root;
+ char *disc_name;
+
+ BLURAY *bdh;
+
+ const BLURAY_DISC_INFO *disc_info;
+ const META_DL *meta_dl; /* disc library meta data */
+
+ int num_title_idx; /* number of relevant playlists */
+ int current_title_idx;
+ int num_titles; /* navigation mode, number of titles in disc index */
+ int current_title; /* navigation mode, title from disc index */
+ BLURAY_TITLE_INFO *title_info;
+ pthread_mutex_t title_info_mutex; /* lock this when accessing title_info outside of input/demux thread */
+ unsigned int current_clip;
+ time_t still_end_time;
+ int pg_stream;
+
+ uint8_t nav_mode : 1;
+ uint8_t error : 1;
+ uint8_t menu_open : 1;
+ uint8_t stream_flushed : 1;
+ uint8_t demux_action_req : 1;
+ uint8_t end_of_title : 1;
+ uint8_t pg_enable : 1;
+ int mouse_inside_button;
+} bluray_input_plugin_t;
+
+/*
+ * overlay
+ */
+
+#define PALETTE_INDEX_BACKGROUND 0xff
+
+static void send_num_buttons(bluray_input_plugin_t *this, int n)
+{
+ xine_event_t event;
+ xine_ui_data_t data;
+
+ event.type = XINE_EVENT_UI_NUM_BUTTONS;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.num_buttons = n;
+
+ xine_event_send(this->stream, &event);
+}
+
+static void clear_overlay(xine_osd_t *osd)
+{
+ /* palette entry 0xff is background --> can't use xine_osd_clear(). */
+ memset(osd->osd.area, PALETTE_INDEX_BACKGROUND, osd->osd.width * osd->osd.height);
+ osd->osd.x1 = osd->osd.width;
+ osd->osd.y1 = osd->osd.height;
+ osd->osd.x2 = 0;
+ osd->osd.y2 = 0;
+}
+
+static xine_osd_t *get_overlay(bluray_input_plugin_t *this, int plane)
+{
+ if (!this->osd[plane]) {
+ this->osd[plane] = xine_osd_new(this->stream, 0, 0, 1920, 1080);
+ clear_overlay(this->osd[plane]);
+ }
+ if (!this->pg_enable) {
+ _x_select_spu_channel(this->stream, -1);
+ }
+ return this->osd[plane];
+}
+
+static void close_overlay(bluray_input_plugin_t *this, int plane)
+{
+ if (plane < 0) {
+ close_overlay(this, 0);
+ close_overlay(this, 1);
+ return;
+ }
+
+ if (plane < 2 && this->osd[plane]) {
+ xine_osd_free(this->osd[plane]);
+ this->osd[plane] = NULL;
+ if (plane == 1) {
+ send_num_buttons(this, 0);
+ this->menu_open = 0;
+ }
+ }
+}
+
+static void open_overlay(bluray_input_plugin_t *this, const BD_OVERLAY * const ov)
+{
+ lprintf("open_overlay(%d,%d)\n", ov->w, ov->h);
+
+ if (this->osd[ov->plane]) {
+ close_overlay(this, ov->plane);
+ }
+
+ this->osd[ov->plane] = xine_osd_new(this->stream, ov->x, ov->y, ov->w, ov->h);
+ clear_overlay(this->osd[ov->plane]);
+}
+
+static void draw_bitmap(xine_osd_t *osd, const BD_OVERLAY * const ov)
+{
+ unsigned i;
+
+ /* convert and set palette */
+ if (ov->palette) {
+ uint32_t color[256];
+ uint8_t trans[256];
+ for(i = 0; i < 256; i++) {
+ trans[i] = ov->palette[i].T;
+ color[i] = (ov->palette[i].Y << 16) | (ov->palette[i].Cr << 8) | ov->palette[i].Cb;
+ }
+
+ xine_osd_set_palette(osd, color, trans);
+ }
+
+ /* uncompress and draw bitmap */
+ if (ov->img) {
+ const BD_PG_RLE_ELEM *rlep = ov->img;
+ uint8_t *img = malloc(ov->w * ov->h);
+ unsigned pixels = ov->w * ov->h;
+
+ for (i = 0; i < pixels; i += rlep->len, rlep++) {
+ memset(img + i, rlep->color, rlep->len);
+ }
+
+ xine_osd_draw_bitmap(osd, img, ov->x, ov->y, ov->w, ov->h, NULL);
+
+ free(img);
+ }
+}
+
+static void overlay_proc(void *this_gen, const BD_OVERLAY * const ov)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+ xine_osd_t *osd;
+
+ if (!this) {
+ return;
+ }
+
+ if (!ov) {
+ /* hide OSD */
+ close_overlay(this, -1);
+ return;
+ }
+
+ if (ov->plane > 1) {
+ return;
+ }
+
+ switch (ov->cmd) {
+ case BD_OVERLAY_INIT:
+ open_overlay(this, ov);
+ return;
+ case BD_OVERLAY_CLOSE:
+ close_overlay(this, ov->plane);
+ return;
+ }
+
+ osd = get_overlay(this, ov->plane);
+
+ switch (ov->cmd) {
+ case BD_OVERLAY_DRAW:
+ draw_bitmap(osd, ov);
+ return;
+
+ case BD_OVERLAY_WIPE:
+ xine_osd_draw_rect(osd, ov->x, ov->y, ov->x + ov->w - 1, ov->y + ov->h - 1, PALETTE_INDEX_BACKGROUND, 1);
+ return;
+
+ case BD_OVERLAY_CLEAR:
+ xine_osd_hide(osd, 0);
+ clear_overlay(osd);
+ return;
+
+ case BD_OVERLAY_FLUSH:
+ xine_osd_show(osd, 0);
+
+ if (ov->plane == 1) {
+ this->menu_open = 1;
+ send_num_buttons(this, 1);
+ }
+ return;
+
+ default:
+ lprintf("unknown overlay command %d\n", ov->cmd);
+ return;
+ }
+}
+
+/*
+ * stream info
+ */
+
+static void update_stream_info(bluray_input_plugin_t *this)
+{
+ if (this->title_info) {
+ /* set stream info */
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_COUNT, this->title_info->angle_count);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh));
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_CHAPTERS, this->title_info->chapter_count > 0);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT, this->title_info->chapter_count);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, bd_get_current_chapter(this->bdh) + 1);
+ }
+}
+
+static void update_title_name(bluray_input_plugin_t *this)
+{
+ char title_name[64] = "";
+ xine_ui_data_t udata;
+ xine_event_t uevent = {
+ .type = XINE_EVENT_UI_SET_TITLE,
+ .stream = this->stream,
+ .data = &udata,
+ .data_length = sizeof(udata)
+ };
+
+ /* check disc library metadata */
+ if (this->meta_dl) {
+ unsigned i;
+ for (i = 0; i < this->meta_dl->toc_count; i++)
+ if (this->meta_dl->toc_entries[i].title_number == (unsigned)this->current_title)
+ if (this->meta_dl->toc_entries[i].title_name)
+ if (strlen(this->meta_dl->toc_entries[i].title_name) > 2)
+ strncpy(title_name, this->meta_dl->toc_entries[i].title_name, sizeof(title_name));
+ }
+
+ /* title name */
+ if (title_name[0]) {
+ } else if (this->current_title == BLURAY_TITLE_TOP_MENU) {
+ strcpy(title_name, "Top Menu");
+ } else if (this->current_title == BLURAY_TITLE_FIRST_PLAY) {
+ strcpy(title_name, "First Play");
+ } else if (this->nav_mode) {
+ snprintf(title_name, sizeof(title_name), "Title %d/%d (PL %d/%d)",
+ this->current_title, this->num_titles,
+ this->current_title_idx + 1, this->num_title_idx);
+ } else {
+ snprintf(title_name, sizeof(title_name), "Title %d/%d",
+ this->current_title_idx + 1, this->num_title_idx);
+ }
+
+ /* disc name */
+ if (this->disc_name && this->disc_name[0]) {
+ udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s, %s",
+ this->disc_name, title_name);
+ } else {
+ udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s",
+ title_name);
+ }
+
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, udata.str);
+
+ xine_event_send(this->stream, &uevent);
+}
+
+static void update_title_info(bluray_input_plugin_t *this, int playlist_id)
+{
+ /* update title_info */
+
+ pthread_mutex_lock(&this->title_info_mutex);
+
+ if (this->title_info)
+ bd_free_title_info(this->title_info);
+
+ if (playlist_id < 0)
+ this->title_info = bd_get_title_info(this->bdh, this->current_title_idx, 0);
+ else
+ this->title_info = bd_get_playlist_info(this->bdh, playlist_id, 0);
+
+ pthread_mutex_unlock(&this->title_info_mutex);
+
+ if (!this->title_info) {
+ LOGMSG("bd_get_title_info(%d) failed\n", this->current_title_idx);
+ return;
+ }
+
+#ifdef LOG
+ int ms = this->title_info->duration / INT64_C(90);
+ lprintf("Opened title %d. Length %"PRId64" bytes / %02d:%02d:%02d.%03d\n",
+ this->current_title_idx, bd_get_title_size(this->bdh),
+ ms / 3600000, (ms % 3600000 / 60000), (ms % 60000) / 1000, ms % 1000);
+#endif
+
+ /* calculate and set stream rate */
+
+ uint64_t rate = bd_get_title_size(this->bdh) * UINT64_C(8) // bits
+ * INT64_C(90000)
+ / (uint64_t)(this->title_info->duration);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, rate);
+
+ /* set stream info */
+
+ if (this->nav_mode) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_titles);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title);
+ } else {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_title_idx);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title_idx + 1);
+ }
+
+ update_stream_info(this);
+
+ /* set title name */
+
+ update_title_name(this);
+}
+
+/*
+ * libbluray event handling
+ */
+
+static void stream_flush(bluray_input_plugin_t *this)
+{
+ if (this->stream_flushed || !this->stream)
+ return;
+
+ lprintf("Stream flush\n");
+
+ this->stream_flushed = 1;
+
+ xine_event_t event = {
+ .type = XINE_EVENT_END_OF_CLIP,
+ .stream = this->stream,
+ .data = NULL,
+ .data_length = 0,
+ };
+ xine_event_send (this->stream, &event);
+
+ this->demux_action_req = 1;
+}
+
+static void stream_reset(bluray_input_plugin_t *this)
+{
+ if (!this || !this->stream)
+ return;
+
+ lprintf("Stream reset\n");
+
+ xine_event_t event = {
+ .type = XINE_EVENT_PIDS_CHANGE,
+ .stream = this->stream,
+ .data = NULL,
+ .data_length = 0,
+ };
+
+ if (!this->end_of_title) {
+ _x_demux_flush_engine(this->stream);
+ }
+
+ xine_event_send (this->stream, &event);
+
+ this->demux_action_req = 1;
+}
+
+static void wait_secs(bluray_input_plugin_t *this, unsigned seconds)
+{
+ stream_flush(this);
+
+ if (this->still_end_time) {
+ if (time(NULL) >= this->still_end_time) {
+ lprintf("pause end\n");
+ this->still_end_time = 0;
+ bd_read_skip_still(this->bdh);
+ stream_reset(this);
+ return;
+ }
+ }
+
+ else if (seconds) {
+ if (seconds > 300) {
+ seconds = 300;
+ }
+
+ lprintf("still image, pause for %d seconds\n", seconds);
+ this->still_end_time = time(NULL) + seconds;
+ }
+
+ xine_usec_sleep(40*1000);
+}
+
+static void update_spu_channel(bluray_input_plugin_t *this, int channel)
+{
+ if (this->stream->video_fifo) {
+ buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
+ buf->type = BUF_CONTROL_SPU_CHANNEL;
+ buf->decoder_info[0] = channel;
+ buf->decoder_info[1] = channel;
+ buf->decoder_info[2] = channel;
+
+ this->stream->video_fifo->put(this->stream->video_fifo, buf);
+ }
+}
+
+static void update_audio_channel(bluray_input_plugin_t *this, int channel)
+{
+ if (this->stream->audio_fifo) {
+ buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo);
+ buf->type = BUF_CONTROL_AUDIO_CHANNEL;
+ buf->decoder_info[0] = channel;
+
+ this->stream->audio_fifo->put(this->stream->audio_fifo, buf);
+ }
+}
+
+static void handle_libbluray_event(bluray_input_plugin_t *this, BD_EVENT ev)
+{
+ switch ((bd_event_e)ev.event) {
+
+ case BD_EVENT_NONE:
+ break;
+
+ case BD_EVENT_ERROR:
+ lprintf("BD_EVENT_ERROR\n");
+ _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
+ "Error playing BluRay disc", NULL);
+ this->error = 1;
+ return;
+
+ case BD_EVENT_READ_ERROR:
+ LOGMSG("BD_EVENT_READ_ERROR\n");
+ return;
+
+ case BD_EVENT_ENCRYPTED:
+ lprintf("BD_EVENT_ENCRYPTED\n");
+ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ "Media stream scrambled/encrypted", NULL);
+ this->error = 1;
+ return;
+
+ /* sound effects */
+#if BLURAY_VERSION >= 202
+ case BD_EVENT_SOUND_EFFECT:
+ lprintf("BD_EVENT_SOUND_EFFECT %d\n", ev.param);
+ break;
+#endif
+
+ /* playback control */
+
+ case BD_EVENT_SEEK:
+ lprintf("BD_EVENT_SEEK\n");
+ this->still_end_time = 0;
+ stream_reset(this);
+ break;
+
+ case BD_EVENT_STILL_TIME:
+ wait_secs(this, ev.param);
+ break;
+
+ case BD_EVENT_STILL:
+ lprintf("BD_EVENT_STILL %d\n", ev.param);
+ int paused = _x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE;
+ if (paused != ev.param) {
+ _x_set_fine_speed(this->stream, ev.param ? XINE_SPEED_PAUSE : XINE_SPEED_NORMAL);
+ }
+ break;
+
+ /* playback position */
+
+ case BD_EVENT_ANGLE:
+ lprintf("BD_EVENT_ANGLE_NUMBER %d\n", ev.param);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, ev.param);
+ break;
+
+ case BD_EVENT_END_OF_TITLE:
+ lprintf("BD_EVENT_END_OF_TITLE\n");
+ stream_flush(this);
+ this->end_of_title = 1;
+ break;
+
+ case BD_EVENT_TITLE:
+ if (this->nav_mode) {
+ lprintf("BD_EVENT_TITLE %d\n", ev.param);
+ this->current_title = ev.param;
+ }
+ break;
+
+ case BD_EVENT_PLAYLIST:
+ lprintf("BD_EVENT_PLAYLIST %d\n", ev.param);
+ this->current_title_idx = bd_get_current_title(this->bdh);
+ this->current_clip = 0;
+ update_title_info(this, ev.param);
+ stream_reset(this);
+ this->end_of_title = 0;
+ break;
+
+ case BD_EVENT_PLAYITEM:
+ lprintf("BD_EVENT_PLAYITEM %d\n", ev.param);
+ this->current_clip = ev.param;
+ this->still_end_time = 0;
+ break;
+
+ case BD_EVENT_CHAPTER:
+ lprintf("BD_EVENT_CHAPTER %d\n", ev.param);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, ev.param);
+ break;
+
+ /* stream selection */
+
+ case BD_EVENT_AUDIO_STREAM:
+ lprintf("BD_EVENT_AUDIO_STREAM %d\n", ev.param);
+ if (ev.param < 32) {
+ update_audio_channel(this, ev.param - 1);
+ } else {
+ update_audio_channel(this, 0);
+ }
+ break;
+
+ case BD_EVENT_PG_TEXTST:
+ lprintf("BD_EVENT_PG_TEXTST %s\n", ev.param ? "ON" : "OFF");
+ this->pg_enable = !!ev.param;
+ update_spu_channel(this, this->pg_enable ? this->pg_stream : -1);
+ break;
+
+ case BD_EVENT_PG_TEXTST_STREAM:
+ lprintf("BD_EVENT_PG_TEXTST_STREAM %d\n", ev.param);
+ if (ev.param < 64) {
+ this->pg_stream = ev.param - 1;
+ } else {
+ this->pg_stream = -1;
+ }
+ if (this->pg_enable) {
+ update_spu_channel(this, this->pg_stream);
+ }
+ break;
+
+ default:
+ lprintf("unhandled libbluray event %d [param %d]\n", ev.event, ev.param);
+ break;
+ }
+}
+
+static void handle_libbluray_events(bluray_input_plugin_t *this)
+{
+ BD_EVENT ev;
+ while (bd_get_event(this->bdh, &ev)) {
+ handle_libbluray_event(this, ev);
+ if (this->error || ev.event == BD_EVENT_NONE || ev.event == BD_EVENT_ERROR)
+ break;
+ }
+}
+
+/*
+ * xine event handling
+ */
+
+static int open_title (bluray_input_plugin_t *this, int title_idx)
+{
+ if (bd_select_title(this->bdh, title_idx) <= 0) {
+ LOGMSG("bd_select_title(%d) failed\n", title_idx);
+ return 0;
+ }
+
+ this->current_title_idx = title_idx;
+
+ update_title_info(this, -1);
+
+ return 1;
+}
+
+static void send_mouse_enter_leave_event(bluray_input_plugin_t *this, int direction)
+{
+ if (direction != this->mouse_inside_button) {
+ xine_event_t event;
+ xine_spu_button_t spu_event;
+
+ spu_event.direction = direction;
+ spu_event.button = 1;
+
+ event.type = XINE_EVENT_SPU_BUTTON;
+ event.stream = this->stream;
+ event.data = &spu_event;
+ event.data_length = sizeof(spu_event);
+ xine_event_send(this->stream, &event);
+
+ this->mouse_inside_button = direction;
+ }
+}
+
+static void handle_events(bluray_input_plugin_t *this)
+{
+ xine_event_t *event;
+
+ if (!this->event_queue)
+ return;
+
+ while (NULL != (event = xine_event_get(this->event_queue))) {
+
+ if (!this->bdh || !this->title_info) {
+ xine_event_free(event);
+ return;
+ }
+
+ int64_t pts = xine_get_current_vpts(this->stream) -
+ this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET);
+
+ if (this->menu_open) {
+ switch (event->type) {
+ case XINE_EVENT_INPUT_LEFT: bd_user_input(this->bdh, pts, BD_VK_LEFT); break;
+ case XINE_EVENT_INPUT_RIGHT: bd_user_input(this->bdh, pts, BD_VK_RIGHT); break;
+ }
+ } else {
+ switch (event->type) {
+
+ case XINE_EVENT_INPUT_LEFT:
+ lprintf("XINE_EVENT_INPUT_LEFT: previous title\n");
+ if (!this->nav_mode) {
+ open_title(this, MAX(0, this->current_title_idx - 1));
+ } else {
+ bd_play_title(this->bdh, MAX(1, this->current_title - 1));
+ }
+ stream_reset(this);
+ break;
+
+ case XINE_EVENT_INPUT_RIGHT:
+ lprintf("XINE_EVENT_INPUT_RIGHT: next title\n");
+ if (!this->nav_mode) {
+ open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1));
+ } else {
+ bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1));
+ }
+ stream_reset(this);
+ break;
+ }
+ }
+
+ switch (event->type) {
+
+ case XINE_EVENT_INPUT_MOUSE_BUTTON: {
+ xine_input_data_t *input = event->data;
+ lprintf("mouse click: button %d at (%d,%d)\n", input->button, input->x, input->y);
+ if (input->button == 1) {
+ bd_mouse_select(this->bdh, pts, input->x, input->y);
+ bd_user_input(this->bdh, pts, BD_VK_MOUSE_ACTIVATE);
+ send_mouse_enter_leave_event(this, 0);
+ }
+ break;
+ }
+
+ case XINE_EVENT_INPUT_MOUSE_MOVE: {
+ xine_input_data_t *input = event->data;
+ if (bd_mouse_select(this->bdh, pts, input->x, input->y) > 0) {
+ send_mouse_enter_leave_event(this, 1);
+ } else {
+ send_mouse_enter_leave_event(this, 0);
+ }
+ break;
+ }
+
+ case XINE_EVENT_INPUT_MENU1:
+ if (!this->disc_info->top_menu_supported) {
+ _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
+ "Can't open Top Menu",
+ "Top Menu title not supported", NULL);
+ }
+ bd_menu_call(this->bdh, pts);
+ break;
+
+ case XINE_EVENT_INPUT_MENU2: bd_user_input(this->bdh, pts, BD_VK_POPUP); break;
+ case XINE_EVENT_INPUT_UP: bd_user_input(this->bdh, pts, BD_VK_UP); break;
+ case XINE_EVENT_INPUT_DOWN: bd_user_input(this->bdh, pts, BD_VK_DOWN); break;
+ case XINE_EVENT_INPUT_SELECT: bd_user_input(this->bdh, pts, BD_VK_ENTER); break;
+ case XINE_EVENT_INPUT_NUMBER_0: bd_user_input(this->bdh, pts, BD_VK_0); break;
+ case XINE_EVENT_INPUT_NUMBER_1: bd_user_input(this->bdh, pts, BD_VK_1); break;
+ case XINE_EVENT_INPUT_NUMBER_2: bd_user_input(this->bdh, pts, BD_VK_2); break;
+ case XINE_EVENT_INPUT_NUMBER_3: bd_user_input(this->bdh, pts, BD_VK_3); break;
+ case XINE_EVENT_INPUT_NUMBER_4: bd_user_input(this->bdh, pts, BD_VK_4); break;
+ case XINE_EVENT_INPUT_NUMBER_5: bd_user_input(this->bdh, pts, BD_VK_5); break;
+ case XINE_EVENT_INPUT_NUMBER_6: bd_user_input(this->bdh, pts, BD_VK_6); break;
+ case XINE_EVENT_INPUT_NUMBER_7: bd_user_input(this->bdh, pts, BD_VK_7); break;
+ case XINE_EVENT_INPUT_NUMBER_8: bd_user_input(this->bdh, pts, BD_VK_8); break;
+ case XINE_EVENT_INPUT_NUMBER_9: bd_user_input(this->bdh, pts, BD_VK_9); break;
+
+ case XINE_EVENT_INPUT_NEXT: {
+ cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config,
+ "media.bluray.skip_behaviour");
+ switch (entry->num_value) {
+ case 0: /* skip by chapter */
+ bd_seek_chapter(this->bdh, bd_get_current_chapter(this->bdh) + 1);
+ update_stream_info(this);
+ break;
+ case 1: /* skip by title */
+ if (!this->nav_mode) {
+ open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1));
+ } else {
+ bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1));
+ }
+ break;
+ }
+ stream_reset(this);
+ break;
+ }
+
+ case XINE_EVENT_INPUT_PREVIOUS: {
+ cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config,
+ "media.bluray.skip_behaviour");
+ switch (entry->num_value) {
+ case 0: /* skip by chapter */
+ bd_seek_chapter(this->bdh, MAX(0, ((int)bd_get_current_chapter(this->bdh)) - 1));
+ update_stream_info(this);
+ break;
+ case 1: /* skip by title */
+ if (!this->nav_mode) {
+ open_title(this, MAX(0, this->current_title_idx - 1));
+ } else {
+ bd_play_title(this->bdh, MAX(1, this->current_title - 1));
+ }
+ break;
+ }
+ stream_reset(this);
+ break;
+ }
+
+ case XINE_EVENT_INPUT_ANGLE_NEXT: {
+ unsigned curr_angle = bd_get_current_angle(this->bdh);
+ unsigned angle = MIN(8, curr_angle + 1);
+ lprintf("XINE_EVENT_INPUT_ANGLE_NEXT: set angle %d --> %d\n", curr_angle, angle);
+ bd_seamless_angle_change(this->bdh, angle);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh));
+ break;
+ }
+
+ case XINE_EVENT_INPUT_ANGLE_PREVIOUS: {
+ unsigned curr_angle = bd_get_current_angle(this->bdh);
+ unsigned angle = curr_angle ? curr_angle - 1 : 0;
+ lprintf("XINE_EVENT_INPUT_ANGLE_PREVIOUS: set angle %d --> %d\n", curr_angle, angle);
+ bd_seamless_angle_change(this->bdh, angle);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh));
+ break;
+ }
+ }
+
+ xine_event_free(event);
+ }
+}
+
+/*
+ * xine plugin interface
+ */
+
+static uint32_t bluray_plugin_get_capabilities (input_plugin_t *this_gen)
+{
+ return INPUT_CAP_SEEKABLE |
+ INPUT_CAP_BLOCK |
+ INPUT_CAP_AUDIOLANG |
+ INPUT_CAP_SPULANG |
+ INPUT_CAP_CHAPTERS;
+}
+
+#define CHECK_READ_INTERRUPT \
+ do { \
+ if (this->demux_action_req) { \
+ this->demux_action_req = 0; \
+ errno = EAGAIN; \
+ return -1; \
+ } \
+ if (_x_action_pending(this->stream)) { \
+ errno = EINTR; \
+ return -1; \
+ } \
+ } while (0)
+
+static off_t bluray_plugin_read (input_plugin_t *this_gen, char *buf, off_t len)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+ off_t result;
+
+ if (!this || !this->bdh || len < 0 || this->error)
+ return -1;
+
+ handle_events(this);
+ CHECK_READ_INTERRUPT;
+
+ if (this->nav_mode) {
+ do {
+ BD_EVENT ev;
+ result = bd_read_ext (this->bdh, (unsigned char *)buf, len, &ev);
+ handle_libbluray_event(this, ev);
+ CHECK_READ_INTERRUPT;
+
+ if (result == 0) {
+ handle_events(this);
+ CHECK_READ_INTERRUPT;
+#if 0
+ if (ev.event == BD_EVENT_NONE) {
+ if (_x_action_pending(this->stream)) {
+ break;
+ }
+ }
+#endif
+ }
+ } while (!this->error && result == 0);
+
+ } else {
+ result = bd_read (this->bdh, (unsigned char *)buf, len);
+ handle_libbluray_events(this);
+ }
+
+ if (result < 0) {
+ LOGMSG("bd_read() failed: %s (%d of %d)\n", strerror(errno), (int)result, (int)len);
+ }
+
+ if (result > 0) {
+ this->stream_flushed = 0;
+ }
+
+ return result;
+}
+
+static buf_element_t *bluray_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo)
+{
+ buf_element_t *buf = fifo->buffer_pool_alloc (fifo);
+
+ if (todo > (off_t)buf->max_size)
+ todo = buf->max_size;
+
+ if (todo > ALIGNED_UNIT_SIZE)
+ todo = ALIGNED_UNIT_SIZE;
+
+ if (todo > 0) {
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ buf->size = bluray_plugin_read(this_gen, (char*)buf->mem, todo);
+ buf->type = BUF_DEMUX_BLOCK;
+
+ if (buf->size > 0) {
+ buf->extra_info->total_time = this->title_info->duration / 90000;
+ return buf;
+ }
+ }
+
+ buf->free_buffer (buf);
+ return NULL;
+}
+
+static off_t bluray_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ if (!this || !this->bdh)
+ return -1;
+ if (this->still_end_time)
+ return offset;
+
+ /* convert relative seeks to absolute */
+
+ if (origin == SEEK_CUR) {
+ offset = bd_tell(this->bdh) + offset;
+ }
+ else if (origin == SEEK_END) {
+ if (offset < (off_t)bd_get_title_size(this->bdh))
+ offset = bd_get_title_size(this->bdh) - offset;
+ else
+ offset = 0;
+ }
+
+ lprintf("bluray_plugin_seek() seeking to %lld\n", (long long)offset);
+
+ return bd_seek (this->bdh, offset);
+}
+
+static off_t bluray_plugin_seek_time (input_plugin_t *this_gen, int time_offset, int origin)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ if (!this || !this->bdh)
+ return -1;
+
+ if (this->still_end_time)
+ return bd_tell(this->bdh);
+
+ /* convert relative seeks to absolute */
+
+ if (origin == SEEK_CUR) {
+ time_offset += this_gen->get_current_time(this_gen);
+ }
+ else if (origin == SEEK_END) {
+
+ pthread_mutex_lock(&this->title_info_mutex);
+
+ if (!this->title_info) {
+ pthread_mutex_unlock(&this->title_info_mutex);
+ return -1;
+ }
+
+ int duration = this->title_info->duration / 90;
+ if (time_offset < duration)
+ time_offset = duration - time_offset;
+ else
+ time_offset = 0;
+
+ pthread_mutex_unlock(&this->title_info_mutex);
+ }
+
+ lprintf("bluray_plugin_seek_time() seeking to %d.%03ds\n", time_offset / 1000, time_offset % 1000);
+
+ return bd_seek_time(this->bdh, time_offset * INT64_C(90));
+}
+
+static off_t bluray_plugin_get_current_pos (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ return this->bdh ? bd_tell(this->bdh) : 0;
+}
+
+static int bluray_plugin_get_current_time (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ return this->bdh ? (int)(bd_tell_time(this->bdh) / UINT64_C(90)) : -1;
+}
+
+static off_t bluray_plugin_get_length (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ return this->bdh ? (off_t)bd_get_title_size(this->bdh) : (off_t)-1;
+}
+
+static uint32_t bluray_plugin_get_blocksize (input_plugin_t *this_gen)
+{
+ return ALIGNED_UNIT_SIZE;
+}
+
+static const char* bluray_plugin_get_mrl (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ return this->mrl;
+}
+
+static int get_audio_lang (bluray_input_plugin_t *this, int *data)
+{
+ /*
+ * audio track language:
+ * - channel number can be mpeg-ts PID (0x1100 ... 0x11ff)
+ */
+
+ unsigned int current_clip = this->current_clip; /* can change any time */
+
+ if (this->title_info && current_clip < this->title_info->clip_count) {
+ int channel = *data;
+ BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip];
+
+ if (channel >= 0 && channel < clip->audio_stream_count) {
+ memcpy(data, clip->audio_streams[channel].lang, 4);
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+
+ /* search by pid */
+ int i;
+ for (i = 0; i < clip->audio_stream_count; i++) {
+ if (channel == clip->audio_streams[i].pid) {
+ memcpy(data, clip->audio_streams[i].lang, 4);
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+ }
+ }
+
+ return INPUT_OPTIONAL_UNSUPPORTED;
+}
+
+static int get_spu_lang (bluray_input_plugin_t *this, int *data)
+{
+ /*
+ * SPU track language:
+ * - channel number can be mpeg-ts PID (0x1200 ... 0x12ff)
+ */
+
+ unsigned int current_clip = this->current_clip; /* can change any time */
+
+ if (this->title_info && current_clip < this->title_info->clip_count) {
+ int channel = *data;
+ BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip];
+
+ if (channel >= 0 && channel < clip->pg_stream_count) {
+ memcpy(data, clip->pg_streams[channel].lang, 4);
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+
+ /* search by pid */
+ int i;
+ for (i = 0; i < clip->pg_stream_count; i++) {
+ if (channel == clip->pg_streams[i].pid) {
+ memcpy(data, clip->pg_streams[i].lang, 4);
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+ }
+ }
+
+ return INPUT_OPTIONAL_UNSUPPORTED;
+}
+
+static int get_optional_data_impl (bluray_input_plugin_t *this, void *data, int data_type)
+{
+ switch (data_type) {
+
+ case INPUT_OPTIONAL_DATA_DEMUXER:
+ if (data)
+ *(const char **)data = "mpeg-ts";
+ return INPUT_OPTIONAL_SUCCESS;
+
+ case INPUT_OPTIONAL_DATA_AUDIOLANG:
+ return get_audio_lang(this, data);
+
+ case INPUT_OPTIONAL_DATA_SPULANG:
+ return get_spu_lang(this, data);
+
+ default:
+ return INPUT_OPTIONAL_UNSUPPORTED;
+ }
+
+ return INPUT_OPTIONAL_UNSUPPORTED;
+}
+
+static int bluray_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+ int r = INPUT_OPTIONAL_UNSUPPORTED;
+
+ if (this && this->stream && data) {
+ pthread_mutex_lock(&this->title_info_mutex);
+ r = get_optional_data_impl(this, data, data_type);
+ pthread_mutex_unlock(&this->title_info_mutex);
+ }
+
+ return r;
+}
+
+static void bluray_plugin_dispose (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ if (this->bdh)
+ bd_register_overlay_proc(this->bdh, NULL, NULL);
+
+ close_overlay(this, -1);
+
+ if (this->event_queue)
+ xine_event_dispose_queue(this->event_queue);
+
+ pthread_mutex_lock(&this->title_info_mutex);
+ if (this->title_info)
+ bd_free_title_info(this->title_info);
+ this->title_info = NULL;
+ pthread_mutex_unlock(&this->title_info_mutex);
+
+ pthread_mutex_destroy(&this->title_info_mutex);
+
+ if (this->bdh)
+ bd_close(this->bdh);
+
+ free (this->mrl);
+ free (this->disc_root);
+ free (this->disc_name);
+
+ free (this);
+}
+
+static int parse_mrl(const char *mrl_in, char **path, int *title, int *chapter)
+{
+ int skip = 0;
+
+ if (!strncasecmp(mrl_in, "bluray:", 7))
+ skip = 7;
+ else if (!strncasecmp(mrl_in, "bd:", 3))
+ skip = 3;
+ else
+ return -1;
+
+ char *mrl = strdup(mrl_in + skip);
+
+ /* title[.chapter] given ? parse and drop it */
+ if (mrl[strlen(mrl)-1] != '/') {
+ char *end = strrchr(mrl, '/');
+ if (end && end[1]) {
+ if (sscanf(end, "/%d.%d", title, chapter) < 1)
+ *title = -1;
+ else
+ *end = 0;
+ }
+ }
+ lprintf(" -> title %d, chapter %d, mrl \'%s\'\n", *title, *chapter, mrl);
+
+ if ((mrl[0] == 0) || !strcmp(mrl, "/") || !strcmp(mrl, "//") || !strcmp(mrl, "///")) {
+
+ /* default device */
+ *path = NULL;
+
+ } else if (*mrl == '/') {
+
+ /* strip extra slashes */
+ char *start = mrl;
+ while (start[0] == '/' && start[1] == '/')
+ start++;
+
+ *path = strdup(start);
+
+ _x_mrl_unescape(*path);
+
+ lprintf("non-defaut mount point \'%s\'\n", *path);
+
+ } else {
+ lprintf("invalid mrl \'%s\'\n", mrl_in);
+ free(mrl);
+ return 0;
+ }
+
+ free(mrl);
+
+ return 1;
+}
+
+static int get_disc_info(bluray_input_plugin_t *this)
+{
+ const BLURAY_DISC_INFO *disc_info;
+
+ disc_info = bd_get_disc_info(this->bdh);
+
+ if (!disc_info) {
+ LOGMSG("bd_get_disc_info() failed\n");
+ return -1;
+ }
+
+ if (!disc_info->bluray_detected) {
+ LOGMSG("bd_get_disc_info(): BluRay not detected\n");
+ this->nav_mode = 0;
+ return 0;
+ }
+
+ if (disc_info->aacs_detected && !disc_info->aacs_handled) {
+ if (!disc_info->libaacs_detected)
+ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ "Media stream scrambled/encrypted with AACS",
+ "libaacs not installed", NULL);
+ else
+ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ "Media stream scrambled/encrypted with AACS", NULL);
+ return -1;
+ }
+
+ if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
+ if (!disc_info->libbdplus_detected)
+ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ "Media scrambled/encrypted with BD+",
+ "libbdplus not installed.", NULL);
+ else
+ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ "Media stream scrambled/encrypted with BD+", NULL);
+ return -1;
+ }
+
+ if (this->nav_mode && !disc_info->first_play_supported) {
+ _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
+ "Can't play disc using menus",
+ "First Play title not supported", NULL);
+ this->nav_mode = 0;
+ }
+
+ if (this->nav_mode && disc_info->num_unsupported_titles > 0) {
+ _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
+ "Unsupported titles found",
+ "Some titles can't be played in navigation mode", NULL);
+ }
+
+ this->num_titles = disc_info->num_hdmv_titles + disc_info->num_bdj_titles;
+ this->disc_info = disc_info;
+
+ return 1;
+}
+
+static char *get_disc_name(const char *path)
+{
+ const char *name_start;
+ char *file_name = NULL;
+ int len;
+
+ name_start = path + strlen(path) - 1;
+ /* skip trailing '/' */
+ while (name_start > path && name_start[0] == '/')
+ name_start--;
+ /* find prev '/' */
+ while (name_start > path && name_start[-1] != '/')
+ name_start--;
+
+ file_name = strdup(name_start);
+ len = strlen(file_name);
+
+ /* trim trailing '/' */
+ while (len > 0 && file_name[len - 1] == '/')
+ file_name[--len] = 0;
+
+ /* trim trailing ".iso" */
+ if (len > 3 && !strcasecmp(file_name + len - 4, ".iso"))
+ file_name[len - 4] = 0;
+
+ /* '_' --> ' ' */
+ for (len = 0; file_name[len]; ++len)
+ if (file_name[len] == '_')
+ file_name[len] = ' ';
+
+ lprintf("disc name: %s\n", file_name);
+ return file_name;
+}
+
+static int is_iso_image(const char *mrl)
+{
+ if (mrl) {
+ const char *pos = strrchr(mrl, '.');
+ return pos && !strcasecmp(pos + 1, "iso");
+ }
+ return 0;
+}
+
+static int bluray_plugin_open (input_plugin_t *this_gen)
+{
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+ int title = -1;
+ int chapter = 0;
+
+ lprintf("bluray_plugin_open '%s'\n",this->mrl);
+
+ /* validate and parse mrl */
+ if (!parse_mrl(this->mrl, &this->disc_root, &title, &chapter))
+ return -1;
+
+ if (!strncasecmp(this->mrl, "bd:", 3))
+ this->nav_mode = 1;
+
+ if (!this->disc_root)
+ this->disc_root = strdup(this->class->mountpoint);
+
+ /* mount .iso image */
+ if (is_iso_image(this->disc_root)) {
+ _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
+ "Can't play BluRay .iso image",
+ "", NULL);
+ return -1;
+ }
+
+ /* open libbluray */
+
+ if (! (this->bdh = bd_open (this->disc_root, NULL))) {
+ LOGMSG("bd_open(\'%s\') failed: %s\n", this->disc_root, strerror(errno));
+ return -1;
+ }
+ lprintf("bd_open(\'%s\') OK\n", this->disc_root);
+
+ if (get_disc_info(this) < 0) {
+ return -1;
+ }
+
+ /* load title list */
+
+ this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH);
+ LOGMSG("%d titles\n", this->num_title_idx);
+
+ if (this->num_title_idx < 1)
+ return -1;
+
+ /* select title */
+
+ /* if title was not in mrl, guess the main title */
+ if (title < 0) {
+ uint64_t duration = 0;
+ int i, playlist = 99999;
+ for (i = 0; i < this->num_title_idx; i++) {
+ BLURAY_TITLE_INFO *info = bd_get_title_info(this->bdh, i, 0);
+ if (info->duration > duration) {
+ title = i;
+ duration = info->duration;
+ playlist = info->playlist;
+ }
+ bd_free_title_info(info);
+ }
+ lprintf("main title: %d (%05d.mpls)\n", title, playlist);
+ }
+
+ /* update player settings */
+
+ bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_REGION_CODE, this->class->region);
+ bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_PARENTAL, this->class->parental);
+ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_AUDIO_LANG, this->class->language);
+ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_PG_LANG, this->class->language);
+ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_MENU_LANG, this->class->language);
+ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_COUNTRY_CODE, this->class->country);
+
+ /* init event queue */
+ bd_get_event(this->bdh, NULL);
+
+ /* get disc name */
+
+ this->meta_dl = bd_get_meta(this->bdh);
+
+ if (this->meta_dl && this->meta_dl->di_name && strlen(this->meta_dl->di_name) > 1) {
+ this->disc_name = strdup(this->meta_dl->di_name);
+ }
+ else if (strcmp(this->disc_root, this->class->mountpoint)) {
+ this->disc_name = get_disc_name(this->disc_root);
+ }
+
+ /* register overlay (graphics) handler */
+
+ bd_register_overlay_proc(this->bdh, this, overlay_proc);
+
+ /* open */
+ this->current_title = -1;
+ this->current_title_idx = -1;
+
+ if (this->nav_mode) {
+ if (bd_play(this->bdh) <= 0) {
+ LOGMSG("bd_play() failed\n");
+ return -1;
+ }
+
+ } else {
+ if (open_title(this, title) <= 0 &&
+ open_title(this, 0) <= 0)
+ return -1;
+ }
+
+ /* jump to chapter */
+
+ if (chapter > 0) {
+ chapter = MAX(0, MIN((int)this->title_info->chapter_count, chapter) - 1);
+ bd_seek_chapter(this->bdh, chapter);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, chapter + 1);
+ }
+
+ return 1;
+}
+
+static input_plugin_t *bluray_class_get_instance (input_class_t *cls_gen, xine_stream_t *stream,
+ const char *mrl)
+{
+ bluray_input_plugin_t *this;
+
+ lprintf("bluray_class_get_instance\n");
+
+ if (strncasecmp(mrl, "bluray:", 7) && strncasecmp(mrl, "bd:", 3))
+ return NULL;
+
+ this = (bluray_input_plugin_t *) calloc(1, sizeof (bluray_input_plugin_t));
+
+ this->stream = stream;
+ this->class = (bluray_input_class_t*)cls_gen;
+ this->mrl = strdup(mrl);
+
+ this->input_plugin.open = bluray_plugin_open;
+ this->input_plugin.get_capabilities = bluray_plugin_get_capabilities;
+ this->input_plugin.read = bluray_plugin_read;
+ this->input_plugin.read_block = bluray_plugin_read_block;
+ this->input_plugin.seek = bluray_plugin_seek;
+ this->input_plugin.seek_time = bluray_plugin_seek_time;
+ this->input_plugin.get_current_pos = bluray_plugin_get_current_pos;
+ this->input_plugin.get_current_time = bluray_plugin_get_current_time;
+ this->input_plugin.get_length = bluray_plugin_get_length;
+ this->input_plugin.get_blocksize = bluray_plugin_get_blocksize;
+ this->input_plugin.get_mrl = bluray_plugin_get_mrl;
+ this->input_plugin.get_optional_data = bluray_plugin_get_optional_data;
+ this->input_plugin.dispose = bluray_plugin_dispose;
+ this->input_plugin.input_class = cls_gen;
+
+ this->event_queue = xine_event_new_queue (this->stream);
+
+ pthread_mutex_init(&this->title_info_mutex, NULL);
+
+ this->pg_stream = -1;
+
+ return &this->input_plugin;
+}
+
+/*
+ * plugin class
+ */
+
+static void mountpoint_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->mountpoint = cfg->str_value;
+}
+
+static void device_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->device = cfg->str_value;
+}
+
+static void language_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->language = cfg->str_value;
+}
+
+static void country_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->country = cfg->str_value;
+}
+
+static void region_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->region = cfg->num_value;
+}
+
+static void parental_change_cb(void *data, xine_cfg_entry_t *cfg)
+{
+ bluray_input_class_t *class = (bluray_input_class_t *) data;
+
+ class->parental = cfg->num_value;
+}
+
+static void free_xine_playlist(bluray_input_class_t *this)
+{
+ if (this->xine_playlist) {
+ int i;
+ for (i = 0; i < this->xine_playlist_size; i++) {
+ MRL_ZERO(this->xine_playlist[i]);
+ free(this->xine_playlist[i]);
+ }
+ free(this->xine_playlist);
+ this->xine_playlist = NULL;
+ }
+
+ this->xine_playlist_size = 0;
+}
+
+static const char *bluray_class_get_description (input_class_t *this_gen)
+{
+ return _("BluRay input plugin");
+}
+
+static const char *bluray_class_get_identifier (input_class_t *this_gen)
+{
+ return "bluray";
+}
+
+static char **bluray_class_get_autoplay_list (input_class_t *this_gen, int *num_files)
+{
+ static char *autoplay_list[] = { "bluray:/", NULL };
+
+ *num_files = 1;
+
+ return autoplay_list;
+}
+
+static xine_mrl_t **bluray_class_get_dir(input_class_t *this_gen, const char *filename, int *nFiles)
+{
+ bluray_input_class_t *this = (bluray_input_class_t*) this_gen;
+ char *path = NULL;
+ int title = -1, chapter = -1, i, num_pl;
+ BLURAY *bdh;
+
+ lprintf("bluray_class_get_dir(%s)\n", filename);
+
+ free_xine_playlist(this);
+
+ if (filename)
+ parse_mrl(filename, &path, &title, &chapter);
+
+ bdh = bd_open(path ? path : this->mountpoint, NULL);
+
+ if (bdh) {
+ num_pl = bd_get_titles(bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH);
+
+ if (num_pl > 0) {
+
+ this->xine_playlist_size = num_pl;
+ this->xine_playlist = calloc(this->xine_playlist_size + 1, sizeof(xine_mrl_t*));
+
+ for (i = 0; i < num_pl; i++) {
+ this->xine_playlist[i] = calloc(1, sizeof(xine_mrl_t));
+
+ this->xine_playlist[i]->origin = _x_asprintf("bluray:/%s", path ? path : "");
+ this->xine_playlist[i]->mrl = _x_asprintf("bluray:/%s/%d", path ? path : "", i);
+ this->xine_playlist[i]->type = mrl_dvd;
+ }
+ }
+
+ bd_close(bdh);
+ }
+
+ free(path);
+
+ if (nFiles)
+ *nFiles = this->xine_playlist_size;
+
+ return this->xine_playlist;
+}
+
+static int bluray_class_eject_media (input_class_t *this_gen)
+{
+ bluray_input_class_t *this = (bluray_input_class_t*) this_gen;
+
+ return media_eject_media (this->xine, this->device);
+}
+
+static void bluray_class_dispose (input_class_t *this_gen)
+{
+ bluray_input_class_t *this = (bluray_input_class_t *) this_gen;
+ config_values_t *config = this->xine->config;
+
+ free_xine_playlist(this);
+
+ config->unregister_callback(config, "media.bluray.mountpoint");
+ config->unregister_callback(config, "media.bluray.device");
+ config->unregister_callback(config, "media.bluray.region");
+ config->unregister_callback(config, "media.bluray.language");
+ config->unregister_callback(config, "media.bluray.country");
+ config->unregister_callback(config, "media.bluray.parental");
+
+ free (this);
+}
+
+static void *bluray_init_plugin (xine_t *xine, void *data)
+{
+ static const char * const skip_modes[] = {"skip chapter", "skip title", NULL};
+
+ config_values_t *config = xine->config;
+ bluray_input_class_t *this = (bluray_input_class_t *) calloc(1, sizeof (bluray_input_class_t));
+
+ this->xine = xine;
+
+ this->input_class.get_instance = bluray_class_get_instance;
+ this->input_class.get_identifier = bluray_class_get_identifier;
+ this->input_class.get_description = bluray_class_get_description;
+ this->input_class.get_dir = bluray_class_get_dir;
+ this->input_class.get_autoplay_list = bluray_class_get_autoplay_list;
+ this->input_class.dispose = bluray_class_dispose;
+ this->input_class.eject_media = bluray_class_eject_media;
+
+ this->mountpoint =
+ config->register_filename(config, "media.bluray.mountpoint",
+ "/mnt/bluray", XINE_CONFIG_STRING_IS_DIRECTORY_NAME,
+ _("BluRay mount point"),
+ _("Default mount location for BluRay discs."),
+ 0, mountpoint_change_cb, (void *) this);
+ this->device =
+ config->register_filename(config, "media.bluray.device",
+ "/dev/dvd", XINE_CONFIG_STRING_IS_DIRECTORY_NAME,
+ _("device used for BluRay playback"),
+ _("The path to the device "
+ "which you intend to use for playing BluRy discs."),
+ 0, device_change_cb, (void *) this);
+
+ /* Player settings */
+ this->language =
+ config->register_string(config, "media.bluray.language",
+ "eng",
+ _("default language for BluRay playback"),
+ _("xine tries to use this language as a default for BluRay playback. "
+ "As far as the BluRay supports it, menus and audio tracks will be presented "
+ "in this language.\nThe value must be a three character"
+ "ISO639-2 language code."),
+ 0, language_change_cb, this);
+ this->country =
+ config->register_string(config, "media.bluray.country",
+ "en",
+ _("BluRay player country code"),
+ _("The value must be a two character ISO3166-1 country code."),
+ 0, country_change_cb, this);
+ this->region =
+ config->register_num(config, "media.bluray.region",
+ 7,
+ _("BluRay player region code (1=A, 2=B, 4=C)"),
+ _("This only needs to be changed if your BluRay jumps to a screen "
+ "complaining about a wrong region code. It has nothing to do with "
+ "the region code set in BluRay drives, this is purely software."),
+ 0, region_change_cb, this);
+ this->parental =
+ config->register_num(config, "media.bluray.parental",
+ 99,
+ _("parental control age limit (1-99)"),
+ _("Prevents playback of BluRay titles where parental "
+ "control age limit is higher than this limit"),
+ 0, parental_change_cb, this);
+
+ /* */
+ config->register_enum(config, "media.bluray.skip_behaviour", 0,
+ skip_modes,
+ _("unit for the skip action"),
+ _("You can configure the behaviour when issuing a skip command (using the skip "
+ "buttons for example)."),
+ 20, NULL, NULL);
+
+ return this;
+}
+
+static const char *bd_class_get_description (input_class_t *this_gen)
+{
+ return _("BluRay input plugin (using menus)");
+}
+
+static const char *bd_class_get_identifier (input_class_t *this_gen)
+{
+ return "bd";
+}
+
+static char **bd_class_get_autoplay_list (input_class_t *this_gen, int *num_files)
+{
+ static char *autoplay_list[] = { "bd:/", NULL };
+
+ *num_files = 1;
+
+ return autoplay_list;
+}
+
+static void *bd_init_plugin (xine_t *xine, void *data)
+{
+ bluray_input_class_t *this = bluray_init_plugin(xine, data);
+
+ if (this) {
+ this->input_class.get_identifier = bd_class_get_identifier;
+ this->input_class.get_description = bd_class_get_description;
+ this->input_class.get_dir = NULL;
+ this->input_class.get_autoplay_list = bd_class_get_autoplay_list;
+ }
+
+ return this;
+}
+
+/*
+ * exported plugin catalog entry
+ */
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BLURAY", XINE_VERSION_CODE, NULL, bluray_init_plugin },
+ { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BD", XINE_VERSION_CODE, NULL, bd_init_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/input/input_net.c b/src/input/input_net.c
index 5c927a6d5..82ab28c1e 100644
--- a/src/input/input_net.c
+++ b/src/input/input_net.c
@@ -113,7 +113,10 @@ typedef struct {
static int host_connect_attempt_ipv4(struct in_addr ia, int port, xine_t *xine) {
int s;
- struct sockaddr_in sin;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr sa;
+ } sa;
s = xine_socket_cloexec(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s==-1) {
@@ -122,14 +125,14 @@ static int host_connect_attempt_ipv4(struct in_addr ia, int port, xine_t *xine)
return -1;
}
- sin.sin_family = AF_INET;
- sin.sin_addr = ia;
- sin.sin_port = htons(port);
+ sa.in.sin_family = AF_INET;
+ sa.in.sin_addr = ia;
+ sa.in.sin_port = htons(port);
#ifndef WIN32
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 && errno != EINPROGRESS)
+ if (connect(s, &sa.sa, sizeof(sa.in))==-1 && errno != EINPROGRESS)
#else
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 && WSAGetLastError() != WSAEINPROGRESS)
+ if (connect(s, &sa.sa, sizeof(sa.in))==-1 && WSAGetLastError() != WSAEINPROGRESS)
#endif
{
xine_log(xine, XINE_LOG_MSG,
diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c
index d187b5c2b..ecea09dbf 100644
--- a/src/input/net_buf_ctrl.c
+++ b/src/input/net_buf_ctrl.c
@@ -162,8 +162,8 @@ static void dvbspeed_init (nbc_t *this) {
#endif
}
if (xine_config_lookup_entry (xine, "engine.buffers.video_num_buffers",
- &entry) && (entry.num_value < 1800)) {
- config->update_num (config, "engine.buffers.video_num_buffers", 1800);
+ &entry) && (entry.num_value < 800)) {
+ config->update_num (config, "engine.buffers.video_num_buffers", 800);
#ifdef LOG_DVBSPEED
printf ("net_buf_ctrl: enlarged video fifo to 1800 buffers\n");
#endif
diff --git a/src/libspudvb/xine_spudvb_decoder.c b/src/libspudvb/xine_spudvb_decoder.c
index 339a6ad80..1ab52b7e7 100644
--- a/src/libspudvb/xine_spudvb_decoder.c
+++ b/src/libspudvb/xine_spudvb_decoder.c
@@ -25,8 +25,9 @@
* - Implement support for teletext based subtitles
*/
-#include "pthread.h"
+#include <pthread.h>
#include <errno.h>
+
#include "xine_internal.h"
#include "bswap.h"
#include "osd.h"
@@ -79,6 +80,8 @@ typedef struct {
typedef struct dvb_spu_class_s {
spu_decoder_class_t class;
xine_t *xine;
+
+ int ignore_pts;
} dvb_spu_class_t;
typedef struct dvb_spu_decoder_s {
@@ -97,9 +100,8 @@ typedef struct dvb_spu_decoder_s {
char *pes_pkt_wrptr;
unsigned int pes_pkt_size;
- uint64_t pts;
- uint64_t vpts;
- uint64_t end_vpts;
+ int64_t vpts;
+ int64_t end_vpts;
pthread_t dvbsub_timer_thread;
struct timespec dvbsub_hide_timeout;
@@ -695,7 +697,7 @@ static void draw_subtitles (dvb_spu_decoder_t * this)
pthread_mutex_lock(&this->dvbsub_osd_mutex);
#ifdef LOG
- printf("SPUDVB: this->vpts=%llu\n",this->vpts);
+ printf("SPUDVB: this->vpts=%"PRId64"\n", this->vpts);
#endif
for ( r=0; r<MAX_REGIONS; r++ ) {
#ifdef LOG
@@ -752,27 +754,29 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
}
return;
}
- else {
- if (buf->decoder_info[2]) {
- memset (this->pes_pkt, 0xff, 64*1024);
- this->pes_pkt_wrptr = this->pes_pkt;
- this->pes_pkt_size = buf->decoder_info[2];
- this->pts = buf->pts;
- xine_fast_memcpy (this->pes_pkt, buf->content, buf->size);
+ /* accumulate data */
+ if (buf->decoder_info[2]) {
+ memset (this->pes_pkt, 0xff, 64*1024);
+ this->pes_pkt_wrptr = this->pes_pkt;
+ this->pes_pkt_size = buf->decoder_info[2];
+
+ xine_fast_memcpy (this->pes_pkt, buf->content, buf->size);
+ this->pes_pkt_wrptr += buf->size;
+
+ this->vpts = 0;
+ }
+ else {
+ if (this->pes_pkt && (this->pes_pkt_wrptr != this->pes_pkt)) {
+ xine_fast_memcpy (this->pes_pkt_wrptr, buf->content, buf->size);
this->pes_pkt_wrptr += buf->size;
}
- else {
- if (this->pes_pkt && (this->pes_pkt_wrptr != this->pes_pkt)) {
- xine_fast_memcpy (this->pes_pkt_wrptr, buf->content, buf->size);
- this->pes_pkt_wrptr += buf->size;
- }
- }
}
+
/* don't ask metronom for a vpts but rather do the calculation
* because buf->pts could be too far in future and metronom won't accept
* further backwards pts (see metronom_got_spu_packet) */
- if (buf->pts) {
+ if (!this->class->ignore_pts && buf->pts > 0) {
metronom_t *const metronom = this->stream->metronom;
const int64_t vpts_offset = metronom->get_option( metronom, METRONOM_VPTS_OFFSET );
const int64_t spu_offset = metronom->get_option( metronom, METRONOM_SPU_OFFSET );
@@ -781,7 +785,7 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
const int64_t curvpts = clock->get_current_time( clock );
/* if buf->pts is unreliable, show page asap (better than nothing) */
#ifdef LOG
- printf("SPUDVB: spu_vpts=%lld - current_vpts=%lld\n", vpts, curvpts);
+ printf("SPUDVB: spu_vpts=%"PRId64" - current_vpts=%"PRId64"\n", vpts, curvpts);
#endif
if ( vpts<=curvpts || (vpts-curvpts)>(5*90000) )
this->vpts = 0;
@@ -790,7 +794,7 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf)
}
/* completely ignore pts since it makes a lot of problems with various providers */
- this->vpts = 0;
+ /* this->vpts = 0; */
/* process the pes section */
@@ -925,8 +929,12 @@ static spu_decoder_t *dvb_spu_class_open_plugin (spu_decoder_class_t * class_gen
return (spu_decoder_t *) this;
}
-static void dvb_spu_class_dispose (spu_decoder_class_t * this)
+static void dvb_spu_class_dispose (spu_decoder_class_t * this_gen)
{
+ dvb_spu_class_t *this = (dvb_spu_class_t *) this_gen;
+
+ this->xine->config->unregister_callback(this->xine->config, "subtitles.dvb.ignore_pts");
+
free (this);
}
@@ -940,6 +948,13 @@ static char *dvb_spu_class_get_description (spu_decoder_class_t * this)
return "DVB subtitle decoder plugin";
}
+static void spu_dvb_ignore_pts_change(void *this_gen, xine_cfg_entry_t *value)
+{
+ dvb_spu_class_t *this = (dvb_spu_class_t *) this_gen;
+
+ this->ignore_pts = value->num_value;
+}
+
static void *init_spu_decoder_plugin (xine_t * xine, void *data)
{
dvb_spu_class_t *this = calloc(1, sizeof (dvb_spu_class_t));
@@ -951,6 +966,12 @@ static void *init_spu_decoder_plugin (xine_t * xine, void *data)
this->xine = xine;
+ this->ignore_pts = xine->config->register_bool(xine->config,
+ "subtitles.dvb.ignore_pts", 0,
+ _("Ignore DVB subtitle timing"),
+ _("Do not use PTS timestamps for DVB subtitle timing"),
+ 1, spu_dvb_ignore_pts_change, this);
+
return &this->class;
}
diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c
index d0a82da09..849346ecd 100644
--- a/src/libspuhdmv/xine_hdmv_decoder.c
+++ b/src/libspuhdmv/xine_hdmv_decoder.c
@@ -267,7 +267,7 @@ static void segbuf_parse_segment_header(segment_buffer_t *buf)
if ( buf->segment_type < 0x14 ||
( buf->segment_type > 0x18 &&
buf->segment_type != 0x80)) {
- XINE_HDMV_ERROR("unknown segment type, resetting\n");
+ XINE_HDMV_ERROR("unknown segment type 0x%02x, resetting\n", buf->segment_type);
segbuf_reset(buf);
}
} else {
diff --git a/src/libsputext/xine_sputext_decoder.c b/src/libsputext/xine_sputext_decoder.c
index 3090c640e..e2e37bc37 100644
--- a/src/libsputext/xine_sputext_decoder.c
+++ b/src/libsputext/xine_sputext_decoder.c
@@ -122,7 +122,7 @@ typedef struct sputext_class_s {
char font_ft[FILENAME_MAX]; /* subtitle font */
int use_font_ft; /* use Freetype */
#endif
- char *src_encoding; /* encoding of subtitle file */
+ const char *src_encoding; /* encoding of subtitle file */
int use_unscaled; /* use unscaled OSD if possible */
xine_t *xine;
diff --git a/src/post/audio/stretch.c b/src/post/audio/stretch.c
index f8047e183..e315b11a8 100644
--- a/src/post/audio/stretch.c
+++ b/src/post/audio/stretch.c
@@ -643,7 +643,7 @@ static post_plugin_t *stretch_open_plugin(post_class_t *class_gen, int inputs,
pthread_mutex_init (&this->lock, NULL);
- set_parameters ((xine_post_t *)&this->post, &init_params);
+ set_parameters (&this->post.xine_post, &init_params);
port = _x_post_intercept_audio_port(&this->post, audio_target[0], &input, &output);
port->new_port.open = stretch_port_open;
diff --git a/src/post/audio/upmix_mono.c b/src/post/audio/upmix_mono.c
index 43fe3df0d..1e5e05549 100644
--- a/src/post/audio/upmix_mono.c
+++ b/src/post/audio/upmix_mono.c
@@ -315,7 +315,7 @@ static post_plugin_t *upmix_mono_open_plugin(post_class_t *class_gen, int inputs
pthread_mutex_init (&this->lock, NULL);
- set_parameters ((xine_post_t *)&this->post, &init_params);
+ set_parameters (&this->post.xine_post, &init_params);
port = _x_post_intercept_audio_port(&this->post, audio_target[0], &input, &output);
port->new_port.open = upmix_mono_port_open;
diff --git a/src/post/deinterlace/xine_plugin.c b/src/post/deinterlace/xine_plugin.c
index 63270acd7..c9d451b4f 100644
--- a/src/post/deinterlace/xine_plugin.c
+++ b/src/post/deinterlace/xine_plugin.c
@@ -397,7 +397,7 @@ static post_plugin_t *deinterlace_open_plugin(post_class_t *class_gen, int input
pthread_mutex_init (&this->lock, NULL);
- set_parameters ((xine_post_t *)&this->post, &class->init_param);
+ set_parameters (&this->post.xine_post, &class->init_param);
port = _x_post_intercept_video_port(&this->post, video_target[0], &input, &output);
/* replace with our own get_frame function */
@@ -449,6 +449,7 @@ static void deinterlace_dispose(post_plugin_t *this_gen)
if (_x_post_dispose(this_gen)) {
_flush_frames(this);
pthread_mutex_destroy(&this->lock);
+ free(this->tvtime);
free(this);
}
}
diff --git a/src/video_out/video_out_fb.c b/src/video_out/video_out_fb.c
index c8697694e..aa066c9c7 100644
--- a/src/video_out/video_out_fb.c
+++ b/src/video_out/video_out_fb.c
@@ -92,7 +92,7 @@ typedef struct fb_frame_s
vo_scale_t sc;
- uint8_t *chunk[3]; /* mem alloc by xmalloc_aligned */
+ void *chunk[3]; /* mem alloc by xmalloc_aligned */
yuv2rgb_t *yuv2rgb; /* yuv2rgb converter for this frame */
uint8_t *rgb_dst;
diff --git a/src/video_out/video_out_opengl.c b/src/video_out/video_out_opengl.c
index 751e39991..3f3000523 100644
--- a/src/video_out/video_out_opengl.c
+++ b/src/video_out/video_out_opengl.c
@@ -224,7 +224,7 @@ typedef void *(*thread_run_t)(void *);
typedef struct {
/* Name of render backend */
- char *name;
+ const char * const name;
/* Finally display current image (needed for Redraw) */
void (*display)(opengl_driver_t *, opengl_frame_t *);
/* Upload new image; Returns 0 if failed */
@@ -673,7 +673,7 @@ static int render_image_envtex (opengl_driver_t *this, opengl_frame_t *frame) {
/*
* Render setup functions
*/
-static int render_help_verify_ext (opengl_driver_t *this, char *ext) {
+static int render_help_verify_ext (opengl_driver_t *this, const char *ext) {
int ret = 0;
const size_t l = strlen (ext);
const char *e;
@@ -924,7 +924,7 @@ static int render_setup_torus (opengl_driver_t *this) {
static int render_setup_fp_yuv (opengl_driver_t *this) {
GLint errorpos;
int ret;
- static char *fragprog_yuv =
+ static const char *fragprog_yuv =
"!!ARBfp1.0\n"
"ATTRIB tex = fragment.texcoord[0];"
"PARAM off = program.env[0];"
@@ -1821,7 +1821,7 @@ static vo_driver_t *opengl_open_plugin (video_driver_class_t *class_gen, const v
config_values_t *config = class->xine->config;
x11_visual_t *visual = (x11_visual_t *) visual_gen;
opengl_driver_t *this;
- char **render_fun_names;
+ const char **render_fun_names;
int i;
this = (opengl_driver_t *) calloc(1, sizeof(opengl_driver_t));
diff --git a/src/video_out/video_out_raw.c b/src/video_out/video_out_raw.c
index 860efdfb7..456b3392f 100644
--- a/src/video_out/video_out_raw.c
+++ b/src/video_out/video_out_raw.c
@@ -61,7 +61,7 @@ typedef struct {
int width, height, format, flags;
double ratio;
- uint8_t *chunk[4]; /* mem alloc by xmalloc_aligned */
+ void *chunk[4]; /* mem alloc by xmalloc_aligned */
uint8_t *rgb, *rgb_dst;
yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */
diff --git a/src/video_out/video_out_xcbshm.c b/src/video_out/video_out_xcbshm.c
index c93cf8c1e..e3556d8e7 100644
--- a/src/video_out/video_out_xcbshm.c
+++ b/src/video_out/video_out_xcbshm.c
@@ -870,7 +870,7 @@ static int xshm_gui_data_exchange (vo_driver_t *this_gen,
break;
case XINE_GUI_SEND_DRAWABLE_CHANGED:
- this->window = (xcb_window_t) data;
+ this->window = (xcb_window_t) (long) data;
pthread_mutex_lock(&this->main_mutex);
xcb_free_gc(this->connection, this->gc);
diff --git a/src/video_out/video_out_xcbxv.c b/src/video_out/video_out_xcbxv.c
index 78bbc94e6..1f580bd69 100644
--- a/src/video_out/video_out_xcbxv.c
+++ b/src/video_out/video_out_xcbxv.c
@@ -968,7 +968,7 @@ static int xv_gui_data_exchange (vo_driver_t *this_gen,
case XINE_GUI_SEND_DRAWABLE_CHANGED:
pthread_mutex_lock(&this->main_mutex);
- this->window = (xcb_window_t) data;
+ this->window = (xcb_window_t) (long) data;
xcb_free_gc(this->connection, this->gc);
this->gc = xcb_generate_id(this->connection);
xcb_create_gc(this->connection, this->gc, this->window, 0, NULL);
@@ -1130,9 +1130,9 @@ static int xv_check_yv12(xcb_connection_t *connection, xcb_xv_port_t port) {
static void xv_check_capability (xv_driver_t *this,
int property, xcb_xv_attribute_info_t *attr,
int base_id,
- char *config_name,
- char *config_desc,
- char *config_help) {
+ const char *config_name,
+ const char *config_desc,
+ const char *config_help) {
int int_default;
cfg_entry_t *entry;
const char *str_prop = xcb_xv_attribute_info_name(attr);
diff --git a/src/video_out/video_out_xvmc.c b/src/video_out/video_out_xvmc.c
index f06f0cf3f..aeb50271a 100644
--- a/src/video_out/video_out_xvmc.c
+++ b/src/video_out/video_out_xvmc.c
@@ -790,7 +790,7 @@ static void xvmc_update_frame_format (vo_driver_t *this_gen,
frame->ratio = ratio;
}
- xvmc->macroblocks = (xine_macroblocks_t *)&this->macroblocks;
+ xvmc->macroblocks = &this->macroblocks.xine_mc;
this->macroblocks.num_blocks = 0;
this->macroblocks.macroblockptr = this->macroblocks.macroblockbaseptr;
this->macroblocks.xine_mc.blockptr =
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index 8f5d1152e..2c13919b8 100644
--- a/src/xine-engine/buffer.h
+++ b/src/xine-engine/buffer.h
@@ -687,7 +687,7 @@ void _x_bmiheader_le2me( xine_bmiheader *bih ) XINE_PROTECTED;
/* convert xine_waveformatex struct from little endian */
void _x_waveformatex_le2me( xine_waveformatex *wavex ) XINE_PROTECTED;
-static __inline int _x_is_fourcc(void *ptr, void *tag) {
+static __inline int _x_is_fourcc(const void *ptr, const void *tag) {
return memcmp(ptr, tag, 4) == 0;
}
diff --git a/src/xine-utils/memcpy.c b/src/xine-utils/memcpy.c
index 9056749e2..df514b682 100644
--- a/src/xine-utils/memcpy.c
+++ b/src/xine-utils/memcpy.c
@@ -408,7 +408,18 @@ static struct {
{ NULL, NULL, 0, 0 }
};
-#if (defined(ARCH_X86) || defined(ARCH_X86_64)) && defined(HAVE_SYS_TIMES_H)
+#ifdef HAVE_POSIX_TIMERS
+/* Prefer clock_gettime() where available. */
+static int64_t _x_gettime(void)
+{
+ struct timespec tm;
+ return (clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tm) == -1)
+ ? times (NULL)
+ : (int64_t)tm.tv_sec * 1e9 + tm.tv_nsec;
+}
+# define rdtsc(x) _x_gettime()
+
+#elif (defined(ARCH_X86) || defined(ARCH_X86_64)) && defined(HAVE_SYS_TIMES_H)
static int64_t rdtsc(int config_flags)
{
int64_t x;
@@ -511,6 +522,12 @@ void xine_probe_fast_memcpy(xine_t *xine)
memset(buf1,0,BUFSIZE);
memset(buf2,0,BUFSIZE);
+ /* some initial activity to ensure that we're not running slowly :-) */
+ for(j=0;j<50;j++) {
+ memcpy_method[1].function(buf2,buf1,BUFSIZE);
+ memcpy_method[1].function(buf1,buf2,BUFSIZE);
+ }
+
for(i=1; memcpy_method[i].name; i++)
{
if( (config_flags & memcpy_method[i].cpu_require) !=