diff options
author | Darren Salt <linux@youmustbejoking.demon.co.uk> | 2011-09-26 00:26:43 +0100 |
---|---|---|
committer | Darren Salt <linux@youmustbejoking.demon.co.uk> | 2011-09-26 00:26:43 +0100 |
commit | a15f6b82252b5afb81486e6f0e9e10e5e2e5ece5 (patch) | |
tree | 099b1d6cc559c3858ad95c9f1dbd56175c5e689f | |
parent | b097a80fb2d9100e02f2fdaf62fe3d408f73763f (diff) | |
parent | 752c9d69932238731394c2b86c458b3213d85b97 (diff) | |
download | xine-lib-a15f6b82252b5afb81486e6f0e9e10e5e2e5ece5.tar.gz xine-lib-a15f6b82252b5afb81486e6f0e9e10e5e2e5ece5.tar.bz2 |
Merge from 1.1. (Needs some testing.)
--HG--
rename : src/xine-engine/buffer.h => include/xine/buffer.h
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | include/xine/buffer.h | 1 | ||||
-rw-r--r-- | m4/attributes.m4 | 10 | ||||
-rw-r--r-- | src/combined/ffmpeg/ff_audio_decoder.c | 40 | ||||
-rw-r--r-- | src/combined/ffmpeg/ff_video_decoder.c | 124 | ||||
-rw-r--r-- | src/combined/ffmpeg/xine_audio.list | 1 | ||||
-rw-r--r-- | src/demuxers/demux_ts.c | 303 | ||||
-rw-r--r-- | src/input/net_buf_ctrl.c | 370 | ||||
-rw-r--r-- | src/xine-engine/buffer_types.c | 8 | ||||
-rw-r--r-- | src/xine-engine/events.c | 4 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 16 |
11 files changed, 546 insertions, 333 deletions
diff --git a/debian/control b/debian/control index f21a303e4..34f3676c5 100644 --- a/debian/control +++ b/debian/control @@ -17,7 +17,7 @@ Build-Depends: debhelper (>= 5.0.1), binutils (>= 2.12.90.0.9), pkg-config, libasound2-dev [!kfreebsd-i386 !kfreebsd-amd64 !hurd-i386], libcam-dev [kfreebsd-i386 kfreebsd-amd64], libaa1-dev, libcaca-dev, libmodplug-dev, - libjack-jackd2-dev | libjack0.100.0-dev, libpulse-dev, libartsc0-dev, + libjack-jackd2-dev | libjack0.100.0-dev, libpulse-dev, graphicsmagick-libmagick-dev-compat | libmagick9-dev | libmagick-dev | libmagickwand-dev, libpng12-dev, libfreetype6-dev, libogg-dev, libvorbis-dev, libtheora-dev, diff --git a/include/xine/buffer.h b/include/xine/buffer.h index 95cdcb69a..bf5d2a98a 100644 --- a/include/xine/buffer.h +++ b/include/xine/buffer.h @@ -268,6 +268,7 @@ extern "C" { #define BUF_AUDIO_AMR_NB 0x033F0000 #define BUF_AUDIO_AMR_WB 0x03400000 #define BUF_AUDIO_EAC3 0x03410000 +#define BUF_AUDIO_AAC_LATM 0x03420000 /*@}*/ /** diff --git a/m4/attributes.m4 b/m4/attributes.m4 index 4f0442865..3d9c256a0 100644 --- a/m4/attributes.m4 +++ b/m4/attributes.m4 @@ -39,7 +39,7 @@ AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" - AC_COMPILE_IFELSE([int a;], + AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) CFLAGS="$ac_save_CFLAGS" @@ -89,7 +89,7 @@ AC_DEFUN([CC_CHECK_LDFLAGS], [ AS_TR_SH([cc_cv_ldflags_$1]), [ac_save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $1" - AC_LINK_IFELSE([int main() { return 1; }], + AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])], [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) LDFLAGS="$ac_save_LDFLAGS" @@ -154,7 +154,7 @@ AC_DEFUN([CC_CHECK_ATTRIBUTE], [ AS_TR_SH([cc_cv_attribute_$1]), [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" - AC_COMPILE_IFELSE([$3], + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) CFLAGS="$ac_save_CFLAGS" @@ -302,11 +302,11 @@ AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" for cc_attribute_align_try in 64 32 16 8 4 2; do - AC_COMPILE_IFELSE([ + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ int main() { static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; return c; - }], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) done CFLAGS="$ac_save_CFLAGS" ]) diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index db2dc8fa2..f2d1ca93f 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -114,7 +114,7 @@ static void *realloc16 (void *m, size_t s) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_audio_dec: increasing buffer to %d to avoid overflow.\n"), this->bufsize); - this->buf = realloc16 (this->buf, this->bufsize); + this->buf = realloc16 (this->buf, this->bufsize + FF_INPUT_BUFFER_PADDING_SIZE); } } @@ -127,14 +127,13 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) int out; audio_buffer_t *audio_buffer; int bytes_to_send; - unsigned int codec_type = buf->type & 0xFFFF0000; + unsigned int codec_type = buf->type & (BUF_MAJOR_MASK | BUF_DECODER_MASK); - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_SPECIAL) ) { + if ( (buf->decoder_flags & (BUF_FLAG_HEADER | BUF_FLAG_SPECIAL)) == BUF_FLAG_HEADER ) { /* accumulate init data */ ff_audio_ensure_buffer_size(this, this->size + buf->size); - memcpy(this->buf + this->size, buf->content, buf->size); + xine_fast_memcpy(this->buf + this->size, buf->content, buf->size); this->size += buf->size; if (buf->decoder_flags & BUF_FLAG_FRAME_END) { @@ -321,27 +320,36 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) if (!this->output_open) { if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + int ret; + decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; #if AVAUDIO > 2 av_init_packet (&avpkt); avpkt.data = (uint8_t *)&this->buf[0]; avpkt.size = this->size; avpkt.flags = AV_PKT_FLAG_KEY; - avcodec_decode_audio3 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, &avpkt); + ret = avcodec_decode_audio3 (this->context, + (int16_t *)this->decode_buffer, + &decode_buffer_size, &avpkt); #else - avcodec_decode_audio2 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, - &this->buf[0], - this->size); + ret = avcodec_decode_audio2 (this->context, + (int16_t *)this->decode_buffer, + &decode_buffer_size, + &this->buf[0], + this->size); #endif this->audio_bits = this->context->bits_per_sample; this->audio_sample_rate = this->context->sample_rate; this->audio_channels = this->context->channels; - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + _("ffmpeg_audio_dec: cannot read codec parameters from packet (error=%d)\n"), ret); + + /* We can't use this packet, so we must discard it + * and wait for another one. */ + this->size = 0; return; + } } this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, this->stream, this->audio_bits, this->audio_sample_rate, @@ -355,6 +363,10 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */ offset = 0; + + /* pad input data */ + memset(&this->buf[this->size], 0, FF_INPUT_BUFFER_PADDING_SIZE); + while (this->size>0) { decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; #if AVAUDIO > 2 diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index 5e4967f6c..03a4b8cac 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -65,6 +65,10 @@ # define pp_mode pp_mode_t #endif +#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 112) +# define DEPRECATED_AVCODEC_THREAD_INIT 1 +#endif + typedef struct ff_video_decoder_s ff_video_decoder_t; typedef struct ff_video_class_s { @@ -354,7 +358,10 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) if (this->class->thread_count > 1) { if (this->codec->id != CODEC_ID_SVQ3 - && avcodec_thread_init(this->context, this->class->thread_count) != -1) +#ifndef DEPRECATED_AVCODEC_THREAD_INIT + && avcodec_thread_init(this->context, this->class->thread_count) != -1 +#endif + ) this->context->thread_count = this->class->thread_count; } @@ -844,6 +851,59 @@ static void ff_check_bufsize (ff_video_decoder_t *this, int size) { } } +static int ff_vc1_find_header(ff_video_decoder_t *this, buf_element_t *buf) +{ + uint8_t *p = buf->content; + + if (!p[0] && !p[1] && p[2] == 1 && p[3] == 0x0f) { + int i; + + this->context->extradata = calloc(1, buf->size); + this->context->extradata_size = 0; + + for (i = 0; i < buf->size && i < 128; i++) { + if (!p[i] && !p[i+1] && p[i+2]) { + lprintf("00 00 01 %02x at %d\n", p[i+3], i); + if (p[i+3] != 0x0e && p[i+3] != 0x0f) + break; + } + this->context->extradata[i] = p[i]; + this->context->extradata_size++; + } + + lprintf("ff_video_decoder: found VC1 sequence header\n"); + return 1; + } + + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_video_dec: VC1 extradata missing !\n"); + return 0; +} + +static int ff_check_extradata(ff_video_decoder_t *this, unsigned int codec_type, buf_element_t *buf) +{ + if (this->context && this->context->extradata) + return 1; + + switch (codec_type) { + case BUF_VIDEO_VC1: + return ff_vc1_find_header(this, buf); + default:; + } + + return 1; +} + +static void ff_init_mpeg12_mode(ff_video_decoder_t *this) +{ + this->is_mpeg12 = 1; + if ( this->mpeg_parser == NULL ) { + this->mpeg_parser = calloc(1, sizeof(mpeg_parser_t)); + mpeg_parser_init(this->mpeg_parser); + this->decoder_init_mode = 0; + } +} + static void ff_handle_preview_buffer (ff_video_decoder_t *this, buf_element_t *buf) { int codec_type; @@ -851,14 +911,14 @@ static void ff_handle_preview_buffer (ff_video_decoder_t *this, buf_element_t *b codec_type = buf->type & 0xFFFF0000; if (codec_type == BUF_VIDEO_MPEG) { - this->is_mpeg12 = 1; - if ( this->mpeg_parser == NULL ) { - this->mpeg_parser = calloc(1, sizeof(mpeg_parser_t)); - mpeg_parser_init(this->mpeg_parser); - } + ff_init_mpeg12_mode(this); } if (this->decoder_init_mode && !this->is_mpeg12) { + + if (!ff_check_extradata(this, codec_type, buf)) + return; + init_video_codec(this, codec_type); init_postprocess(this); this->decoder_init_mode = 0; @@ -1024,6 +1084,11 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu lprintf("handle_mpeg12_buffer\n"); + if (!this->is_mpeg12) { + /* initialize mpeg parser */ + ff_init_mpeg12_mode(this); + } + while ((size > 0) || (flush == 1)) { uint8_t *current; @@ -1198,49 +1263,6 @@ static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts) } } -static int ff_vc1_find_header(ff_video_decoder_t *this, buf_element_t *buf) -{ - uint8_t *p = buf->content; - - if (!p[0] && !p[1] && p[2] == 1 && p[3] == 0x0f) { - int i; - - this->context->extradata = calloc(1, buf->size); - this->context->extradata_size = 0; - - for (i = 0; i < buf->size && i < 128; i++) { - if (!p[i] && !p[i+1] && p[i+2]) { - lprintf("00 00 01 %02x at %d\n", p[i+3], i); - if (p[i+3] != 0x0e && p[i+3] != 0x0f) - break; - } - this->context->extradata[i] = p[i]; - this->context->extradata_size++; - } - - lprintf("ff_video_decoder: found VC1 sequence header\n"); - return 1; - } - - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "ffmpeg_video_dec: VC1 extradata missing !\n"); - return 0; -} - -static int ff_check_extradata(ff_video_decoder_t *this, unsigned int codec_type, buf_element_t *buf) -{ - if (this->context && this->context->extradata) - return 1; - - switch (codec_type) { - case BUF_VIDEO_VC1: - return ff_vc1_find_header(this, buf); - default:; - } - - return 1; -} - static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { uint8_t *chunk_buf = this->buf; AVRational avr00 = {0, 1}; @@ -1249,7 +1271,7 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { if (!this->decoder_ok) { if (this->decoder_init_mode) { - int codec_type = buf->type & 0xFFFF0000; + int codec_type = buf->type & (BUF_MAJOR_MASK | BUF_DECODER_MASK); if (!ff_check_extradata(this, codec_type, buf)) return; @@ -1569,7 +1591,7 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { if (buf->pts) this->pts = buf->pts; - if (this->is_mpeg12) { + if ((buf->type & 0xFFFF0000) == BUF_VIDEO_MPEG) { ff_handle_mpeg12_buffer(this, buf); } else { ff_handle_buffer(this, buf); diff --git a/src/combined/ffmpeg/xine_audio.list b/src/combined/ffmpeg/xine_audio.list index 796917dfe..8a40c29cb 100644 --- a/src/combined/ffmpeg/xine_audio.list +++ b/src/combined/ffmpeg/xine_audio.list @@ -41,6 +41,7 @@ WAVPACK WAVPACK WavPack AMR_NB AMR_NB AMR narrow band AMR_WB AMR_WB AMR wide band EAC3 EAC3 E-AC-3 +AAC_LATM AAC_LATM AAC LATM # disabled codecs (ref. configure.ac) ! AAC diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c index 49880f9a2..74840885d 100644 --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -277,11 +277,10 @@ typedef struct { int64_t pts; buf_element_t *buf; unsigned int counter; + unsigned int numPreview; uint16_t descriptor_tag; /* +0x100 for PES stream IDs (no available TS descriptor tag?) */ - int64_t packet_count; int corrupted_pes; uint32_t buffered_bytes; - int autodetected; } demux_ts_media; @@ -352,17 +351,12 @@ typedef struct { * and audio PIDs, we keep the index of the corresponding entry * inthe media[] array. */ - unsigned int programNumber; - unsigned int pcrPid; - unsigned int pid; - unsigned int pid_count; unsigned int videoPid; unsigned int videoMedia; demux_ts_audio_track audio_tracks[MAX_AUDIO_TRACKS]; int audio_tracks_count; - int send_end_buffers; int64_t last_pts[2]; int send_newpts; int buf_flag_seek; @@ -390,8 +384,6 @@ typedef struct { uint8_t buf[BUF_SIZE]; /* == PKT_SIZE * NPKT_PER_READ */ - int numPreview; - } demux_ts_t; /* redefine abs as macro to handle 64-bit diffs. @@ -634,7 +626,7 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, */ program_count = 0; for (program = pkt + 13; - program < pkt + 13 + section_length - 9; + (program < pkt + 13 + section_length - 9) && (program_count < MAX_PMTS); program += 4) { program_number = ((unsigned int)program[0] << 8) | program[1]; pmt_pid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; @@ -646,18 +638,14 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, continue; /* - * If we have yet to learn our program number, then learn it, - * use this loop to eventually add support for dynamically changing - * PATs. + * Add the program number to the table if we haven't already + * seen it. The order of the program numbers is assumed not + * to change between otherwise identical PATs. */ - program_count = 0; - - while ((this->program_number[program_count] != INVALID_PROGRAM) && - (this->program_number[program_count] != program_number) && - (program_count+1 < MAX_PMTS ) ) { - program_count++; + if (this->program_number[program_count] != program_number) { + this->program_number[program_count] = program_number; + this->pmt_pid[program_count] = INVALID_PID; } - this->program_number[program_count] = program_number; /* force PMT reparsing when pmt_pid changes */ if (this->pmt_pid[program_count] != pmt_pid) { @@ -681,21 +669,32 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, this->program_number[program_count], this->pmt_pid[program_count]); #endif + + ++program_count; + } + + /* Add "end of table" markers. */ + if (program_count < MAX_PMTS) { + this->program_number[program_count] = INVALID_PROGRAM; + this->pmt_pid[program_count] = INVALID_PID; } } static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, - uint8_t *buf, int packet_len, - xine_stream_t *stream) { + uint8_t *buf, int packet_len) { unsigned char *p; uint32_t header_len; int64_t pts; uint32_t stream_id; - int pkt_len; + + if (packet_len < 9) { + xprintf (xine, XINE_VERBOSITY_DEBUG, + "demux_ts: too short PES packet header (%d bytes)\n", packet_len); + return 0; + } p = buf; - pkt_len = packet_len; /* we should have a PES packet here */ @@ -705,14 +704,14 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, return 0 ; } - packet_len -= 6; /* packet_len = p[4] << 8 | p[5]; */ stream_id = p[3]; + header_len = p[8]; - if (packet_len==0) - { + /* sometimes corruption on header_len causes segfault in memcpy below */ + if (header_len + 9 > packet_len) { xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: error pes length 0\n"); + "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len); return 0; } @@ -723,6 +722,10 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, if (p[7] & 0x80) { /* pts avail */ + if (header_len < 5) { + return 0; + } + pts = (int64_t)(p[ 9] & 0x0E) << 29 ; pts |= p[10] << 22 ; pts |= (p[11] & 0xFE) << 14 ; @@ -747,17 +750,8 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, m->pts = pts; - header_len = p[8]; - - /* sometimes corruption on header_len causes segfault in memcpy below */ - if (header_len + 9 > pkt_len) { - xprintf (xine, XINE_VERBOSITY_DEBUG, - "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len); - return 0; - } - p += header_len + 9; - packet_len -= header_len + 3; + packet_len -= header_len + 9; if (m->descriptor_tag == STREAM_VIDEO_VC1) { m->content = p; @@ -797,7 +791,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, return 1; } else if((m->descriptor_tag == STREAM_AUDIO_AC3) || /* ac3 - raw */ - (p[0] == 0x0B && p[1] == 0x77)) { /* ac3 - syncword */ + (packet_len > 1 && p[0] == 0x0B && p[1] == 0x77)) { /* ac3 - syncword */ m->content = p; m->size = packet_len; m->type |= BUF_AUDIO_A52; @@ -817,8 +811,15 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, m->type |= BUF_AUDIO_DTS; return 1; + } else if (packet_len < 2) { + return 0; + } else if (m->descriptor_tag == HDMV_AUDIO_80_PCM) { + if (packet_len < 4) { + return 0; + } + m->content = p + 4; m->size = packet_len - 4; m->type |= BUF_AUDIO_LPCM_BE; @@ -848,6 +849,10 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, return 1; } else if ((p[0] & 0xF0) == 0x80) { + if (packet_len < 4) { + return 0; + } + m->content = p+4; m->size = packet_len - 4; m->type |= BUF_AUDIO_A52; @@ -864,13 +869,17 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, } } + if (packet_len < pcm_offset) { + return 0; + } + m->content = p+pcm_offset; m->size = packet_len-pcm_offset; m->type |= BUF_AUDIO_LPCM_BE; return 1; } - } else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) { + } else if ((stream_id & 0xf0) == 0xe0) { m->content = p; m->size = packet_len; @@ -907,10 +916,13 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, m->type |= BUF_AUDIO_MPEG; break; case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: lprintf ("demux_ts: found AAC audio track.\n"); m->type |= BUF_AUDIO_AAC; break; + case ISO_14496_PART3_AUDIO: + lprintf ("demux_ts: found AAC LATM audio track.\n"); + m->type |= BUF_AUDIO_AAC_LATM; + break; default: lprintf ("demux_ts: unknown audio type: %d, defaulting to MPEG.\n", m->descriptor_tag); m->type |= BUF_AUDIO_MPEG; @@ -929,6 +941,14 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, /* + * Track how many of these types of packets we have seen in this stream. + */ +static inline unsigned get_preview_frame_number(unsigned *numPreview, unsigned limit) { + unsigned preview = *numPreview; + return (preview < limit) ? ++(*numPreview) : preview; +} + +/* * buffer arriving pes data */ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, @@ -958,26 +978,45 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, m->counter++; if (pus) { /* new PES packet */ - if (m->buffered_bytes) { + unsigned previewLimit = 0; + m->buf->content = m->buf->mem; m->buf->size = m->buffered_bytes; m->buf->type = m->type; - if( (m->buf->type & 0xffff0000) == BUF_SPU_DVD ) { - m->buf->decoder_flags |= BUF_FLAG_SPECIAL; - m->buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; - m->buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; + + switch (m->type & BUF_MAJOR_MASK) { + case BUF_SPU_BASE: + if( (m->buf->type & (BUF_MAJOR_MASK | BUF_DECODER_MASK)) == BUF_SPU_DVB ) { + /* TODO: DVBSUB handling needed? */ + } + break; + + case BUF_VIDEO_BASE: + previewLimit = 5; + break; + + case BUF_AUDIO_BASE: + previewLimit = 2; + break; + + default: + break; } - else { - if (this->numPreview<5) - ++this->numPreview; - if ( this->numPreview==1 ) - m->buf->decoder_flags=BUF_FLAG_HEADER | BUF_FLAG_FRAME_END; - else if ( this->numPreview<5 ) - m->buf->decoder_flags=BUF_FLAG_PREVIEW; - else - m->buf->decoder_flags |= BUF_FLAG_FRAME_END; + + if (previewLimit != 0) { + unsigned numPreview; + + numPreview = get_preview_frame_number(&m->numPreview, previewLimit); + + if (numPreview == 1) + m->buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_FRAME_END; + else if (numPreview < previewLimit) + m->buf->decoder_flags = BUF_FLAG_PREVIEW; + else + m->buf->decoder_flags |= BUF_FLAG_FRAME_END; } + m->buf->pts = m->pts; m->buf->decoder_info[0] = 1; @@ -997,20 +1036,13 @@ 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, this->stream)) { + if (!demux_ts_parse_pes_header(this->stream->xine, m, ts, len)) { m->buf->free_buffer(m->buf); m->buf = NULL; - if (m->corrupted_pes > CORRUPT_PES_THRESHOLD && m->autodetected) { - if (this->videoPid == m->pid) { - this->videoPid = INVALID_PID; - this->last_pmt_crc = 0; - } - } else { - m->corrupted_pes++; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: PID 0x%.4x: corrupted pes encountered\n", m->pid); - } + m->corrupted_pes++; + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ts: PID 0x%.4x: corrupted pes encountered\n", m->pid); } else { m->corrupted_pes = 0; @@ -1065,6 +1097,7 @@ static void demux_ts_pes_new(demux_ts_t*this, if (m->buf != NULL) m->buf->free_buffer(m->buf); m->buf = NULL; m->counter = INVALID_CC; + m->numPreview = 0; m->descriptor_tag = descriptor; m->corrupted_pes = 1; m->buffered_bytes = 0; @@ -1135,6 +1168,15 @@ static inline int ts_payloadsize(unsigned char * tsp) return 184; } +/* check if an apid is in the list of known apids */ +static int apid_check(demux_ts_t*this, unsigned int pid) { + int i; + for (i = 0; i < this->audio_tracks_count; i++) { + if (this->audio_tracks[i].pid == pid) + return i; + } + return -1; +} /* * NAME demux_ts_parse_pmt @@ -1181,7 +1223,7 @@ static void demux_ts_parse_pmt (demux_ts_t *this, pkt+=pkt[4]; /* pointer to start of section */ offset=1; - if (this->pmt[program_count] != NULL) free(this->pmt[program_count]); + free(this->pmt[program_count]); this->pmt[program_count] = (uint8_t *) calloc(4096, sizeof(unsigned char)); this->pmt_write_ptr[program_count] = this->pmt[program_count]; @@ -1384,14 +1426,7 @@ 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) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { + if (apid_check(this, pid) < 0) { #ifdef TS_PMT_LOG printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]); #endif @@ -1422,14 +1457,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num case ISO_13818_PES_PRIVATE: for (i = 5; i < coded_length; i += stream[i+1] + 2) { if (((stream[i] == 0x6a) || (stream[i] == 0x7a)) && (this->audio_tracks_count < MAX_AUDIO_TRACKS)) { - int j, found = 0; - for(j = 0; j < this->audio_tracks_count; j++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if (!found) { + if (apid_check(this, pid) < 0) { #ifdef TS_PMT_LOG printf ("demux_ts: PMT AC3 audio pid 0x%.4x type %2.2x\n", pid, stream[0]); #endif @@ -1548,14 +1576,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num * FIXME: This will need expanding if we ever see a DTS or other media format here. */ if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { + if (apid_check(this,pid) < 0) { uint32_t format_identifier=0; demux_ts_get_reg_desc(this, &format_identifier, stream + 5, stream_info_length); @@ -1591,6 +1612,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num section_length -= coded_length; } +#if 0 /* * Get the current PCR PID. */ @@ -1606,6 +1628,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num #endif this->pcrPid = pid; } +#endif if ( this->stream->spu_channel>=0 && this->spu_langs_count>0 ) demux_ts_update_spu_channel( this ); @@ -1801,6 +1824,9 @@ static int64_t demux_ts_adaptation_field_parse(uint8_t *data, } #endif if(PCR_flag) { + if (adaptation_field_length < offset + 6) + return 0; + PCR = (((int64_t) data[offset]) & 0xFF) << 25; PCR += (int64_t) ((data[offset+1] & 0xFF) << 17); PCR += (int64_t) ((data[offset+2] & 0xFF) << 9); @@ -1815,6 +1841,9 @@ static int64_t demux_ts_adaptation_field_parse(uint8_t *data, offset+=6; } if(OPCR_flag) { + if (adaptation_field_length < offset + 6) + return PCR; + OPCR = data[offset] << 25; OPCR |= data[offset+1] << 17; OPCR |= data[offset+2] << 9; @@ -1844,16 +1873,6 @@ static int64_t demux_ts_adaptation_field_parse(uint8_t *data, return PCR; } -/* check if an apid is in the list of known apids */ -static int apid_check(demux_ts_t*this, unsigned int pid) { - int i; - for(i=0; i<this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) - return i; - } - return -1; -} - /* transport stream packet layer */ static void demux_ts_parse_packet (demux_ts_t*this) { @@ -1922,8 +1941,10 @@ static void demux_ts_parse_packet (demux_ts_t*this) { for (i=0; i < this->scrambled_npids; i++) { if (this->scrambled_pids[i] == pid) return; } - this->scrambled_pids[this->scrambled_npids] = pid; - this->scrambled_npids++; + if (this->scrambled_npids < MAX_PIDS) { + this->scrambled_pids[this->scrambled_npids] = pid; + this->scrambled_npids++; + } xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: PID 0x%.4x is scrambled!\n", pid); return; @@ -1970,69 +1991,10 @@ static void demux_ts_parse_packet (demux_ts_t*this) { program_count++; } - if (payload_unit_start_indicator && this->media_num < MAX_PIDS){ - int pes_stream_id; - if (pid == 0) { - demux_ts_parse_pat (this, originalPkt, originalPkt+data_offset-4, - payload_unit_start_indicator); - return; - } - program_count = 0; - pes_stream_id = originalPkt[data_offset+3]; - -#ifdef TS_HEADER_LOG - printf("demux_ts:ts_pes_header:stream_id=0x%.2x\n",pes_stream_id); -#endif - - if ( (pes_stream_id >= VIDEO_STREAM_S) && (pes_stream_id <= VIDEO_STREAM_E) ) { - if ( this->videoPid == INVALID_PID) { - int i, found = 0; - for(i = 0; i < this->media_num; i++) { - if (this->media[i].pid == pid) { - found = 1; - break; - } - } - - if (found && (this->media[i].corrupted_pes == 0)) { - this->videoPid = pid; - this->videoMedia = i; - } else if (!found) { - this->videoPid = pid; - this->videoMedia = this->media_num; - this->media[this->videoMedia].autodetected = 1; - demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, 0x100 + pes_stream_id); - } - - if (this->videoPid != INVALID_PID) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: auto-detected video pid 0x%.4x\n", pid); - } - } - } else if ( (pes_stream_id >= AUDIO_STREAM_S) && (pes_stream_id <= AUDIO_STREAM_E) ) { - if (this->audio_tracks_count < MAX_AUDIO_TRACKS) { - int i, found = 0; - for(i = 0; i < this->audio_tracks_count; i++) { - if(this->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if(!found) { -#ifdef TS_PMT_LOG - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: auto-detected audio pid 0x%.4x\n", pid); -#endif - /* store PID, index and stream no. */ - this->audio_tracks[this->audio_tracks_count].pid = pid; - this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; - this->media[this->media_num].type = this->audio_tracks_count; - demux_ts_pes_new(this, this->media_num++, pid, - this->audio_fifo, 0x100 + pes_stream_id); - this->audio_tracks_count++; - } - } - } + if (payload_unit_start_indicator && (this->media_num < MAX_PIDS) && (pid == 0)) { + demux_ts_parse_pat(this, originalPkt, originalPkt+data_offset-4, + payload_unit_start_indicator); + return; } if (data_len > PKT_SIZE) { @@ -2194,7 +2156,6 @@ static void demux_ts_send_headers (demux_plugin_t *this_gen) { this->status = DEMUX_OK ; - this->send_end_buffers = 1; this->scrambled_npids = 0; /* DVBSUB */ @@ -2382,7 +2343,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->stream = stream; this->input = input; this->class = class_gen; - this->blockSize = PKT_SIZE; this->demux_plugin.send_headers = demux_ts_send_headers; this->demux_plugin.send_chunk = demux_ts_send_chunk; @@ -2400,7 +2360,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, for (i = 0; i < MAX_PIDS; i++) { this->media[i].pid = INVALID_PID; this->media[i].buf = NULL; - this->media[i].autodetected = 0; } for (i = 0; i < MAX_PMTS; i++) { @@ -2410,8 +2369,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->pmt_write_ptr[i] = NULL; } - this->programNumber = INVALID_PROGRAM; - this->pcrPid = INVALID_PID; this->scrambled_npids = 0; this->videoPid = INVALID_PID; this->audio_tracks_count = 0; @@ -2434,8 +2391,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->pkt_offset = (hdmv > 0) ? 4 : 0; this->pkt_size = PKT_SIZE + this->pkt_offset; - this->numPreview=0; - return &this->demux_plugin; } @@ -2459,7 +2414,7 @@ static void *init_class (xine_t *xine, void *data) { * mrl formats: the content is exactly the same but the input plugin * uses a different tuning algorithm [Pragma] */ - this->demux_class.extensions = "ts m2t trp dvb:// dvbs:// dvbc:// dvbt://"; + this->demux_class.extensions = "ts m2t trp m2ts mts dvb:// dvbs:// dvbc:// dvbt://"; this->demux_class.dispose = default_demux_class_dispose; this->av_crc = av_crc_get_table(AV_CRC_32_IEEE); diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c index d777a0cc9..81165afcf 100644 --- a/src/input/net_buf_ctrl.c +++ b/src/input/net_buf_ctrl.c @@ -36,6 +36,8 @@ */ +#define LOG_DVBSPEED + #include "net_buf_ctrl.h" #define DEFAULT_HIGH_WATER_MARK 5000 /* in 1/1000 s */ @@ -79,6 +81,18 @@ struct nbc_s { int audio_in_disc; pthread_mutex_t mutex; + + /* follow live dvb delivery speed. + 0 = fix disabled + 1 = play at normal speed + 2 = play 0.5% slower to fill video fifo + 3 = play 0.5% faster to empty video fifo + 4..6 = same as 1..3 but watch audio fifo instead + 7 = pause */ + int dvbspeed; + int dvbs_center, dvbs_width, dvbs_audio_fill, dvbs_video_fill; + int64_t dvbs_audio_in, dvbs_audio_out; + int64_t dvbs_video_in, dvbs_video_out; }; static void report_progress (xine_stream_t *stream, int p) { @@ -112,6 +126,190 @@ static void nbc_set_speed_normal (nbc_t *this) { stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1); } +static void dvbspeed_init (nbc_t *this) { + const char *mrl; + if (this->stream && this->stream->input_plugin) { + mrl = this->stream->input_plugin->get_mrl (this->stream->input_plugin); + if (mrl) { + /* detect Kaffeine: fifo://~/.kde4/share/apps/kaffeine/dvbpipe.m2t */ + if ((strcasestr (mrl, "/dvbpipe.")) || + ((!strncasecmp (mrl, "dvb", 3)) && + ((mrl[3] == ':') || (mrl[3] && (mrl[4] == ':'))))) { + this->dvbs_center = 2 * 90000; + this->dvbs_width = 90000; + this->dvbs_audio_in = this->dvbs_audio_out = this->dvbs_audio_fill = 0; + this->dvbs_video_in = this->dvbs_video_out = this->dvbs_video_fill = 0; + this->dvbspeed = 7; +#ifdef LOG_DVBSPEED + /* I'm using plain printf because kaffeine sets verbosity to 0 */ + printf ("net_buf_ctrl: dvbspeed mode\n"); +#endif +#if 1 + /* somewhat rude but saves user a lot of frustration */ + if (this->stream) { + xine_t *xine = this->stream->xine; + config_values_t *config = xine->config; + xine_cfg_entry_t entry; + if (xine_config_lookup_entry (xine, "audio.synchronization.slow_fast_audio", + &entry) && (entry.num_value == 0)) { + config->update_num (config, "audio.synchronization.slow_fast_audio", 1); +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: slow/fast audio playback enabled\n"); +#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); +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: enlarged video fifo to 1800 buffers\n"); +#endif + } + } +#endif + } + } + } +} + +static void dvbspeed_close (nbc_t *this) { + if (((0xec >> this->dvbspeed) & 1) && this->stream) + _x_set_fine_speed (this->stream, XINE_FINE_SPEED_NORMAL); +#ifdef LOG_DVBSPEED + if (this->dvbspeed) printf ("net_buf_ctrl: dvbspeed OFF\n"); +#endif + this->dvbspeed = 0; +} + +static void dvbspeed_put (nbc_t *this, fifo_buffer_t * fifo, buf_element_t *b) { + int64_t diff, *last; + int *fill; + int used, mode; + const char *name; + /* select vars */ + if (fifo == this->video_fifo) { + last = &this->dvbs_video_in; + fill = &this->dvbs_video_fill; + mode = 0x71; + name = "video"; + } else if (fifo == this->audio_fifo) { + last = &this->dvbs_audio_in; + fill = &this->dvbs_audio_fill; + mode = 0x0f; + name = "audio"; + } else return; + /* update fifo fill time */ + if (b->pts && (b->decoder_flags & BUF_FLAG_FRAME_START)) { + if (*last) { + diff = b->pts - *last; + if ((diff > -220000) && (diff < 220000)) *fill += diff; + } + *last = b->pts; + } + /* take actions */ + if ((mode >> this->dvbspeed) & 1) return; + used = fifo->fifo_size; + switch (this->dvbspeed) { + case 1: + case 4: + if ((*fill > this->dvbs_center + this->dvbs_width) || + (100 * used > 98 * fifo->buffer_pool_capacity)) { + _x_set_fine_speed (this->stream, XINE_FINE_SPEED_NORMAL * 201 / 200); + this->dvbspeed += 2; +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: dvbspeed 100.5%% @ %s %d ms %d buffers\n", + name, (int)*fill / 90, used); +#endif + } + break; + case 7: + if (_x_get_fine_speed (this->stream)) { + /* Pause on first a/v buffer. Decoder headers went through at this time + already, and xine_play is done waiting for that */ + _x_set_fine_speed (this->stream, 0); +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: prebuffering...\n"); +#endif + break; + } + /* DVB streams usually mux video > 0.5 seconds earlier than audio + to give slow TVs time to decode and present in sync. Take care + of unusual high delays of some DVB-T streams */ + if (this->dvbs_audio_in && this->dvbs_video_in) { + int64_t d = this->dvbs_video_in - this->dvbs_audio_in + 110000; + if ((d < 3 * 90000) && (d > this->dvbs_center)) this->dvbs_center = d; + } + /* fall through */ + case 2: + case 5: + if ((*fill > this->dvbs_center) || (100 * used > 73 * fifo->buffer_pool_capacity)) { + _x_set_fine_speed (this->stream, XINE_FINE_SPEED_NORMAL); + this->dvbspeed = (mode & 0x10) ? 1 : 4; +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: dvbspeed 100%% @ %s %d ms %d buffers\n", + name, (int)*fill / 90, used); +#endif + /* dont let low bitrate radio switch speed too often */ + if (used < 30) this->dvbs_width = 135000; + } + break; + } +} + +static void dvbspeed_get (nbc_t *this, fifo_buffer_t * fifo, buf_element_t *b) { + int64_t diff, *last; + int *fill; + int used, mode; + const char *name; + /* select vars */ + if (fifo == this->video_fifo) { + last = &this->dvbs_video_out; + fill = &this->dvbs_video_fill; + mode = 0x71; + name = "video"; + } else if (fifo == this->audio_fifo) { + last = &this->dvbs_audio_out; + fill = &this->dvbs_audio_fill; + mode = 0x0f; + name = "audio"; + } else return; + /* update fifo fill time */ + if (b->pts && (b->decoder_flags & BUF_FLAG_FRAME_START)) { + if (*last) { + diff = b->pts - *last; + if ((diff > -220000) && (diff < 220000)) *fill -= diff; + } + *last = b->pts; + } + /* take actions */ + used = fifo->fifo_size; + if (((mode >> this->dvbspeed) & 1) || !*fill) return; + switch (this->dvbspeed) { + case 1: + case 4: + if ((*fill < this->dvbs_center - this->dvbs_width) && + (100 * used < 38 * fifo->buffer_pool_capacity)) { + _x_set_fine_speed (this->stream, XINE_FINE_SPEED_NORMAL * 199 / 200); + this->dvbspeed += 1; +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: dvbspeed 99.5%% @ %s %d ms %d buffers\n", + name, (int)*fill / 90, used); +#endif + } + break; + case 3: + case 6: + if ((*fill < this->dvbs_center) && (100 * used < 73 * fifo->buffer_pool_capacity)) { + _x_set_fine_speed (this->stream, XINE_FINE_SPEED_NORMAL); + this->dvbspeed -= 2; +#ifdef LOG_DVBSPEED + printf ("net_buf_ctrl: dvbspeed 100%% @ %s %d ms %d buffers\n", + name, (int)*fill / 90, used); +#endif + } + break; + } +} + static void display_stats (nbc_t *this) { static const char buffering[2][4] = {" ", "buf"}; static const char enabled[2][4] = {"off", "on "}; @@ -304,69 +502,73 @@ static void nbc_put_cb (fifo_buffer_t *fifo, if (this->enabled) { - nbc_compute_fifo_length(this, fifo, buf, FIFO_PUT); - - if (this->buffering) { - - has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO); - has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO); - /* restart playing if high_water_mark is reached by all fifos - * do not restart if has_video and has_audio are false to avoid - * a yoyo effect at the beginning of the stream when these values - * are not yet known. - * - * be sure that the next buffer_pool_alloc() call will not deadlock, - * we need at least 2 buffers (see buffer.c) - */ - if ((((!has_video) || (this->video_fifo_length > this->high_water_mark)) && - ((!has_audio) || (this->audio_fifo_length > this->high_water_mark)) && - (has_video || has_audio))) { + if (this->dvbspeed) + dvbspeed_put (this, fifo, buf); + else { + nbc_compute_fifo_length(this, fifo, buf, FIFO_PUT); + + if (this->buffering) { + + has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO); + has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO); + /* restart playing if high_water_mark is reached by all fifos + * do not restart if has_video and has_audio are false to avoid + * a yoyo effect at the beginning of the stream when these values + * are not yet known. + * + * be sure that the next buffer_pool_alloc() call will not deadlock, + * we need at least 2 buffers (see buffer.c) + */ + if ((((!has_video) || (this->video_fifo_length > this->high_water_mark)) && + ((!has_audio) || (this->audio_fifo_length > this->high_water_mark)) && + (has_video || has_audio))) { - this->progress = 100; - report_progress (this->stream, 100); - this->buffering = 0; + this->progress = 100; + report_progress (this->stream, 100); + this->buffering = 0; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: nbc_put_cb: stops buffering\n"); + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: nbc_put_cb: stops buffering\n"); - nbc_set_speed_normal(this); + nbc_set_speed_normal(this); - this->high_water_mark += this->high_water_mark / 2; + this->high_water_mark += this->high_water_mark / 2; - } else { - /* compute the buffering progress - * 50%: video - * 50%: audio */ - video_p = ((this->video_fifo_length * 50) / this->high_water_mark); - if (video_p > 50) video_p = 50; - audio_p = ((this->audio_fifo_length * 50) / this->high_water_mark); - if (audio_p > 50) audio_p = 50; - - if ((has_video) && (has_audio)) { - progress = video_p + audio_p; - } else if (has_video) { - progress = 2 * video_p; } else { - progress = 2 * audio_p; - } - - /* if the progress can't be computed using the fifo length, - use the number of buffers */ - if (!progress) { - video_p = this->video_fifo_fill; - audio_p = this->audio_fifo_fill; - progress = (video_p > audio_p) ? video_p : audio_p; - } - - if (progress > this->progress) { - report_progress (this->stream, progress); - this->progress = progress; + /* compute the buffering progress + * 50%: video + * 50%: audio */ + video_p = ((this->video_fifo_length * 50) / this->high_water_mark); + if (video_p > 50) video_p = 50; + audio_p = ((this->audio_fifo_length * 50) / this->high_water_mark); + if (audio_p > 50) audio_p = 50; + + if ((has_video) && (has_audio)) { + progress = video_p + audio_p; + } else if (has_video) { + progress = 2 * video_p; + } else { + progress = 2 * audio_p; + } + + /* if the progress can't be computed using the fifo length, + use the number of buffers */ + if (!progress) { + video_p = this->video_fifo_fill; + audio_p = this->audio_fifo_fill; + progress = (video_p > audio_p) ? video_p : audio_p; + } + + if (progress > this->progress) { + report_progress (this->stream, progress); + this->progress = progress; + } } } - } - if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) - display_stats(this); + if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) + display_stats(this); - report_stats(this, 0); + report_stats(this, 0); + } } } else { @@ -384,7 +586,8 @@ static void nbc_put_cb (fifo_buffer_t *fifo, this->audio_last_pts = 0; this->video_fifo_length = 0; this->audio_fifo_length = 0; - nbc_set_speed_pause(this); + dvbspeed_init (this); + if (!this->dvbspeed) nbc_set_speed_pause(this); this->progress = 0; report_progress (this->stream, progress); } @@ -398,6 +601,7 @@ static void nbc_put_cb (fifo_buffer_t *fifo, case BUF_CONTROL_END: case BUF_CONTROL_QUIT: lprintf("BUF_CONTROL_END\n"); + dvbspeed_close (this); if (this->enabled) { /* end of stream : * - disable the nbc @@ -458,36 +662,40 @@ static void nbc_get_cb (fifo_buffer_t *fifo, if (this->enabled) { - nbc_compute_fifo_length(this, fifo, buf, FIFO_GET); - - if (!this->buffering) { - /* start buffering if one fifo is empty - */ - int has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO); - int has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO); - if (((this->video_fifo_length == 0) && has_video) || - ((this->audio_fifo_length == 0) && has_audio)) { - /* do not pause if a fifo is full to avoid yoyo (play-pause-play-pause) */ - if ((this->video_fifo_free > FULL_FIFO_MARK) && - (this->audio_fifo_free > FULL_FIFO_MARK)) { - this->buffering = 1; - this->progress = 0; - report_progress (this->stream, 0); - - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "\nnet_buf_ctrl: nbc_get_cb: starts buffering, vid: %d, aud: %d\n", - this->video_fifo_fill, this->audio_fifo_fill); - nbc_set_speed_pause(this); + if (this->dvbspeed) + dvbspeed_get (this, fifo, buf); + else { + nbc_compute_fifo_length(this, fifo, buf, FIFO_GET); + + if (!this->buffering) { + /* start buffering if one fifo is empty + */ + int has_video = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO); + int has_audio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO); + if (((this->video_fifo_length == 0) && has_video) || + ((this->audio_fifo_length == 0) && has_audio)) { + /* do not pause if a fifo is full to avoid yoyo (play-pause-play-pause) */ + if ((this->video_fifo_free > FULL_FIFO_MARK) && + (this->audio_fifo_free > FULL_FIFO_MARK)) { + this->buffering = 1; + this->progress = 0; + report_progress (this->stream, 0); + + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "\nnet_buf_ctrl: nbc_get_cb: starts buffering, vid: %d, aud: %d\n", + this->video_fifo_fill, this->audio_fifo_fill); + nbc_set_speed_pause(this); + } } + } else { + nbc_set_speed_pause(this); } - } else { - nbc_set_speed_pause(this); - } - if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) - display_stats(this); + if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) + display_stats(this); - report_stats(this, 1); + report_stats(this, 1); + } } } else { /* discontinuity management */ diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index 6f45672ee..55661c381 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -1194,6 +1194,14 @@ static const audio_db_t audio_db[] = { BUF_AUDIO_EAC3, "E-AC-3" }, +{ + { + ME_FOURCC('M', 'P', '4', 'L'), + 0 + }, + BUF_AUDIO_AAC_LATM, + "AAC LATM" +}, { { 0 }, 0, "last entry" } }; diff --git a/src/xine-engine/events.c b/src/xine-engine/events.c index 11d6e8bd7..5bd827c45 100644 --- a/src/xine-engine/events.c +++ b/src/xine-engine/events.c @@ -111,6 +111,8 @@ xine_event_queue_t *xine_event_new_queue (xine_stream_t *stream) { xine_event_queue_t *queue; + _x_refcounter_inc(stream->refcounter); + queue = malloc (sizeof (xine_event_queue_t)); pthread_mutex_init (&queue->lock, NULL); @@ -186,6 +188,8 @@ void xine_event_dispose_queue (xine_event_queue_t *queue) { free (queue->listener_thread); } + _x_refcounter_dec(stream->refcounter); + /* * clean up pending events */ diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 6e5001f35..d3a75623b 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -1519,6 +1519,14 @@ static void xine_dispose_internal (xine_stream_t *stream) { xine_list_iterator_t *ite; lprintf("stream: %p\n", stream); + + pthread_mutex_lock(&stream->xine->streams_lock); + ite = xine_list_find(stream->xine->streams, stream); + if (ite) { + xine_list_remove(stream->xine->streams, ite); + } + pthread_mutex_unlock(&stream->xine->streams_lock); + pthread_mutex_destroy (&stream->info_mutex); pthread_mutex_destroy (&stream->meta_mutex); pthread_mutex_destroy (&stream->frontend_lock); @@ -1537,13 +1545,6 @@ static void xine_dispose_internal (xine_stream_t *stream) { xine_list_delete(stream->event_queues); - pthread_mutex_lock(&stream->xine->streams_lock); - ite = xine_list_find(stream->xine->streams, stream); - if (ite) { - xine_list_remove(stream->xine->streams, ite); - } - pthread_mutex_unlock(&stream->xine->streams_lock); - _x_refcounter_dispose(stream->refcounter); free (stream->current_extra_info); @@ -1581,6 +1582,7 @@ void xine_dispose (xine_stream_t *stream) { if (stream->osd_renderer) stream->osd_renderer->close( stream->osd_renderer ); + /* Remove the reference that the stream was created with. */ _x_refcounter_dec(stream->refcounter); } |