summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThibaut Mattern <tmattern@users.sourceforge.net>2003-03-30 15:19:45 +0000
committerThibaut Mattern <tmattern@users.sourceforge.net>2003-03-30 15:19:45 +0000
commitc26901e3c59aa88bc0071633a667430316b1ded4 (patch)
tree5589f8fa0be58cae5631577328f5c327b4cb018d /src
parent939c40b7ab92c779734e5aa15a7714b1ae54b26b (diff)
downloadxine-lib-c26901e3c59aa88bc0071633a667430316b1ded4.tar.gz
xine-lib-c26901e3c59aa88bc0071633a667430316b1ded4.tar.bz2
New net_buf_ctrl.
See xine-devel for details. Basicaly it adds callbacks to fifo, and everything is done at fifo level now. It fixes deadlocks with ogg/ogm streams, pauses the engine at the right time, and evaluates better the length of the data in fifos (using pts when the bitrate is not constant). Enjoy. CVS patchset: 4513 CVS date: 2003/03/30 15:19:45
Diffstat (limited to 'src')
-rw-r--r--src/input/net_buf_ctrl.c493
-rw-r--r--src/xine-engine/buffer.c67
-rw-r--r--src/xine-engine/buffer.h18
-rw-r--r--src/xine-engine/demux.c29
-rw-r--r--src/xine-engine/xine.c58
5 files changed, 477 insertions, 188 deletions
diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c
index 649b34c22..a53bab639 100644
--- a/src/input/net_buf_ctrl.c
+++ b/src/input/net_buf_ctrl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2002 the xine project
+ * Copyright (C) 2000-2003 the xine project
*
* This file is part of xine, a free video player.
*
@@ -31,8 +31,12 @@
#include "net_buf_ctrl.h"
#define DEFAULT_LOW_WATER_MARK 1
-#define DEFAULT_HIGH_WATER_MARK 5000 /* in millisecond */
+#define DEFAULT_HIGH_WATER_MARK 5000 /* in 1/1000 s */
+#define WRAP_THRESHOLD 5*90000 /* from the asf demuxer */
+
+#define FIFO_PUT 0
+#define FIFO_GET 1
/*
#define LOG
*/
@@ -42,11 +46,31 @@ struct nbc_s {
xine_stream_t *stream;
int buffering;
- int low_water_mark;
- int high_water_mark;
- int fifo_full;
- int progress;
+ int enabled;
+ int progress;
+ fifo_buffer_t *video_fifo;
+ fifo_buffer_t *audio_fifo;
+ int video_fifo_fill;
+ int audio_fifo_fill;
+ int video_fifo_free;
+ int audio_fifo_free;
+ int64_t video_fifo_length; /* in ms */
+ int64_t audio_fifo_length; /* in ms */
+
+ int64_t low_water_mark;
+ int64_t high_water_mark;
+ /* bitrate */
+ int64_t video_last_pts;
+ int64_t audio_last_pts;
+ int64_t video_first_pts;
+ int64_t audio_first_pts;
+ int64_t video_fifo_size;
+ int64_t audio_fifo_size;
+ int64_t video_br;
+ int64_t audio_br;
+
+ pthread_mutex_t mutex;
};
static void report_progress (xine_stream_t *stream, int p) {
@@ -64,167 +88,368 @@ static void report_progress (xine_stream_t *stream, int p) {
xine_event_send (stream, &event);
}
+static void nbc_set_speed_pause (xine_stream_t *stream) {
+#ifdef LOG
+ printf("\nnet_buf_ctrl: nbc_put_cb: set_speed_pause\n");
+#endif
+ stream->xine->clock->set_speed (stream->xine->clock, XINE_SPEED_PAUSE);
+ stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 0);
+ if (stream->audio_out)
+ stream->audio_out->set_property(stream->audio_out,AO_PROP_PAUSED,2);
+}
+static void nbc_set_speed_normal (xine_stream_t *stream) {
+#ifdef LOG
+ printf("\nnet_buf_ctrl: nbc_put_cb: set_speed_normal\n");
+#endif
+ stream->xine->clock->set_speed (stream->xine->clock, XINE_SPEED_NORMAL);
+ stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
+ if (stream->audio_out)
+ stream->audio_out->set_property(stream->audio_out,AO_PROP_PAUSED,0);
+}
void nbc_check_buffers (nbc_t *this) {
+ /* Deprecated */
+}
- int fifo_fill, video_fifo_fill, audio_fifo_fill; /* number of buffers */
- int video_fifo_free, audio_fifo_free; /* number of free buffers */
- int data_length, video_data_length, audio_data_length; /* fifo length in second */
- uint32_t video_data_size, audio_data_size; /* fifo size in bytes */
- int video_bitrate, audio_bitrate;
- int progress;
- int video_fifo_progress, audio_fifo_progress;
-
- video_fifo_fill = this->stream->video_fifo->size(this->stream->video_fifo);
- if (this->stream->audio_fifo)
- audio_fifo_fill = this->stream->audio_fifo->size(this->stream->audio_fifo);
- else
- audio_fifo_fill = 0;
-
- fifo_fill = video_fifo_fill + audio_fifo_fill;
-
- /* start buffering if fifos are empty */
- if (fifo_fill == 0) {
- if (!this->buffering) {
-
- /* increase/decrease marks to adapt to stream/network needs */
- if (!this->fifo_full) {
- this->high_water_mark += this->high_water_mark / 4;
- /* this->low_water_mark = this->high_water_mark/4; */
- } else {
- this->high_water_mark -= this->high_water_mark / 8;
- }
- this->buffering = 1;
- this->progress = 0;
- report_progress (this->stream, 0);
+static void display_stats (nbc_t *this) {
+
+ if (this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) {
+ printf("net_buf_ctrl: vff=%3d%% aff=%3d%% vf=%4.1fs af=%4.1fs vbr=%4lld abr=%4lld b=%1d e=%1d\r",
+ this->video_fifo_fill, this->audio_fifo_fill,
+ (float)(this->video_fifo_length / 1000),
+ (float)(this->audio_fifo_length / 1000),
+ this->video_br / 1000, this->audio_br / 1000,
+ this->buffering, this->enabled
+ );
+ fflush(stdout);
+ }
+}
- }
- /* pause */
- this->stream->xine->clock->set_speed (this->stream->xine->clock, XINE_SPEED_PAUSE);
- this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 0);
- if (this->stream->audio_out)
- this->stream->audio_out->set_property(this->stream->audio_out,AO_PROP_PAUSED,2);
+void nbc_close (nbc_t *this) {
+ fifo_buffer_t *video_fifo = this->stream->video_fifo;
+ fifo_buffer_t *audio_fifo = this->stream->audio_fifo;
- } else {
+#ifdef LOG
+ printf("\nnet_buf_ctrl: nbc_close\n");
+#endif
- if (this->buffering) {
+ video_fifo->register_put_cb(video_fifo, NULL, NULL);
+ video_fifo->register_get_cb(video_fifo, NULL, NULL);
- /* compute data length in fifos */
- video_bitrate = this->stream->stream_info[XINE_STREAM_INFO_VIDEO_BITRATE];
- audio_bitrate = this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITRATE];
+ if (audio_fifo) {
+ audio_fifo->register_put_cb(audio_fifo, NULL, NULL);
+ audio_fifo->register_get_cb(audio_fifo, NULL, NULL);
+ }
- if (video_bitrate) {
- video_data_size = this->stream->video_fifo->data_size(this->stream->video_fifo);
- video_data_length = (8000 * video_data_size) / video_bitrate;
- } else {
- video_data_length = 0;
- }
- video_fifo_free = this->stream->video_fifo->num_free(this->stream->video_fifo);
+ pthread_mutex_lock(&this->mutex);
+ this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
- if (this->stream->audio_fifo) {
- if (audio_bitrate) {
- audio_data_size = this->stream->audio_fifo->data_size(this->stream->audio_fifo);
- audio_data_length = (8000 * audio_data_size) / audio_bitrate;
- } else {
- audio_data_length = 0;
- }
- audio_fifo_free = this->stream->audio_fifo->num_free(this->stream->audio_fifo);
- } else {
- audio_data_length = 0;
- audio_fifo_free = 0;
- }
+ if (this->buffering) {
+ this->buffering = 0;
+ nbc_set_speed_normal(this->stream);
+ }
- data_length = (video_data_length > audio_data_length) ? video_data_length : audio_data_length;
+ pthread_mutex_unlock(&this->mutex);
+ free (this);
#ifdef LOG
- printf("net_buf_ctrl: vb=%d, ab=%d, vf=%d, af=%d, vdl=%d, adl=%d, dl=%d\r",
- video_fifo_fill, audio_fifo_fill,
- video_fifo_free, audio_fifo_free,
- video_data_length, audio_data_length, data_length);
- fflush(stdout);
+ printf("\nnet_buf_ctrl: nbc_close: done\n");
#endif
- /* stop buffering because:
- * - fifos are filled enough
- * - fifos are full (1 buffer is keeped for emergency stuffs)
- */
- if ((data_length >= this->high_water_mark) ||
- (video_fifo_free == 1) ||
- (audio_fifo_free == 1) ) {
-
- /* unpause */
+}
+
+/* Try to compute the length of the fifo in 1/1000 s
+ * 2 methods :
+ * if the bitrate is known
+ * use the size of the fifo
+ * else
+ * use the the first and the last pts of the fifo
+ */
+static void nbc_compute_fifo_length(nbc_t *this,
+ fifo_buffer_t *fifo,
+ buf_element_t *buf,
+ int action) {
+ int fifo_free, fifo_fill;
+ int64_t video_br, audio_br;
+ int has_video, has_audio;
+ int64_t pts_diff = 0;
+
+ has_video = this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO];
+ has_audio = this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO];
+ video_br = this->stream->stream_info[XINE_STREAM_INFO_VIDEO_BITRATE];
+ audio_br = this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITRATE];
+
+ fifo_free = fifo->buffer_pool_num_free;
+ fifo_fill = fifo->fifo_size;
+
+ if (fifo == this->video_fifo) {
+ this->video_fifo_free = fifo_free;
+ this->video_fifo_fill = (100 * fifo_fill) / (fifo_fill + fifo_free - 1);
+ this->video_fifo_size = fifo->fifo_data_size;
+ if (video_br) {
+ this->video_br = video_br;
+ this->video_fifo_length = (8000 * this->video_fifo_size) / this->video_br;
+ } else {
+ if (buf->pts) {
+ if (action == FIFO_PUT) {
+ pts_diff = buf->pts - this->video_last_pts;
+ if ((pts_diff >= 0) && (pts_diff < WRAP_THRESHOLD)) {
+ this->video_last_pts = buf->pts;
+ } else {
+ /* discontinuity detected */
#ifdef LOG
- printf("\n");
+ printf("\nnet_buf_ctrl: nbc_compute_fifo_length: video discontinuity: %lld\n", pts_diff);
#endif
- this->stream->xine->clock->set_speed (this->stream->xine->clock, XINE_SPEED_NORMAL);
- this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
- if (this->stream->audio_out)
- this->stream->audio_out->set_property(this->stream->audio_out,AO_PROP_PAUSED,0);
-
- report_progress (this->stream, 100);
- this->buffering = 0;
- this->fifo_full = (data_length < this->high_water_mark);
- } else {
- progress = (data_length * 100) / this->high_water_mark;
-
- if (!progress) {
- /* bitrate is not known */
- if ((video_fifo_fill + video_fifo_free) > 0)
- video_fifo_progress = (100 * video_fifo_fill) / (video_fifo_fill + video_fifo_free);
- else
- video_fifo_progress = 0;
- if ((audio_fifo_fill + audio_fifo_free) > 0)
- audio_fifo_progress = (100 * audio_fifo_fill) / (audio_fifo_fill + audio_fifo_free);
- else
- audio_fifo_progress = 0;
- progress = (video_fifo_progress > audio_fifo_progress)?
- video_fifo_progress : audio_fifo_progress;
+ this->video_last_pts = buf->pts;
+ /* smooth the discontinuity */
+ this->video_first_pts = buf->pts - 90 * this->video_fifo_length;
+ }
+ if (this->video_first_pts == 0) {
+ this->video_first_pts = buf->pts;
+ }
+ } else {
+ this->video_first_pts = buf->pts;
}
-
- if (progress != this->progress) {
- report_progress (this->stream, progress);
- this->progress = progress;
+ this->video_fifo_length = (this->video_last_pts - this->video_first_pts) / 90;
+ if (this->video_fifo_length)
+ this->video_br = 8000 * (this->video_fifo_size / this->video_fifo_length);
+ else
+ this->video_br = 0;
+ }
+ }
+ } else {
+ this->audio_fifo_free = fifo_free;
+ this->audio_fifo_fill = (100 * fifo_fill) / (fifo_fill + fifo_free - 1);
+ this->audio_fifo_size = fifo->fifo_data_size;
+ if (audio_br) {
+ this->audio_br = audio_br;
+ this->audio_fifo_length = (8000 * this->audio_fifo_size) / this->audio_br;
+ } else {
+ if (buf->pts) {
+ if (action == FIFO_PUT) {
+ pts_diff = buf->pts - this->audio_last_pts;
+ if ((pts_diff >= 0) && (pts_diff < WRAP_THRESHOLD)) {
+ this->audio_last_pts = buf->pts;
+ } else {
+ /* discontinuity detected */
+#ifdef LOG
+ printf("\nnet_buf_ctrl: nbc_compute_fifo_length: audio discontinuity: %lld\n", pts_diff);
+#endif
+ this->audio_last_pts = buf->pts;
+ /* smooth the discontinuity */
+ this->audio_first_pts = buf->pts - 90 * this->audio_fifo_length;
+ }
+ if (!this->audio_first_pts) {
+ this->audio_first_pts = buf->pts;
+ }
+ } else {
+ this->audio_first_pts = buf->pts;
}
+ this->audio_fifo_length = (this->audio_last_pts - this->audio_first_pts) / 90;
+ if (this->audio_fifo_length)
+ this->audio_br = 8000 * (this->audio_fifo_size / this->audio_fifo_length);
+ else
+ this->audio_br = 0;
}
+ }
+ }
+}
+
+/* Put callback
+ * the fifo mutex is locked */
+void nbc_put_cb (fifo_buffer_t *fifo, buf_element_t *buf, void *this_gen) {
+ nbc_t *this = (nbc_t*)this_gen;
+ int64_t progress = 0;
+ int64_t video_p = 0;
+ int64_t audio_p = 0;
+ int has_video, has_audio;
+ uint32_t buf_major_mask;
+
+ pthread_mutex_lock(&this->mutex);
+
+ /* stop buffering at the end of the stream */
+ if ((buf->decoder_flags & BUF_FLAG_END_USER) ||
+ (buf->decoder_flags & BUF_FLAG_END_STREAM)) {
+ this->enabled = 0;
+ if (this->buffering) {
+ this->buffering = 0;
+ nbc_set_speed_normal(this->stream);
+ }
+ }
+
+ /* do nothing if we are at the end of the stream */
+ if (!this->enabled) {
+
+ buf_major_mask = buf->type & BUF_MAJOR_MASK;
+ if ((buf_major_mask == BUF_VIDEO_BASE) || (buf_major_mask == BUF_AUDIO_BASE)) {
+ /* a new stream starts */
+ if (this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ printf("\nnet_buf_ctrl: nbc_put_cb: starts buffering\n");
+ this->enabled = 1;
+ this->buffering = 1;
+ this->video_first_pts = 0;
+ this->video_last_pts = 0;
+ this->audio_first_pts = 0;
+ this->audio_last_pts = 0;
+ this->video_fifo_length = 0;
+ this->audio_fifo_length = 0;
+ nbc_set_speed_pause(this->stream);
+ this->progress = 0;
+ report_progress (this->stream, progress);
} else {
- /* fifos are ok */
+ display_stats(this);
+ pthread_mutex_unlock(&this->mutex);
+ return;
}
+ }
+
+ nbc_compute_fifo_length(this, fifo, buf, FIFO_PUT);
+
+ if (this->buffering) {
+
+ has_video = this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO];
+ has_audio = this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO];
+ /* restart playing if :
+ * - one fifo is full (to avoid deadlock)
+ * - 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. */
+ if ((fifo->buffer_pool_num_free <= 1) ||
+ (((!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;
+ if (this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ printf("\nnet_buf_ctrl: nbc_put_cb: stops buffering\n");
+
+ nbc_set_speed_normal(this->stream);
+
+ } 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;
+ }
+ }
}
+ display_stats(this);
+ pthread_mutex_unlock(&this->mutex);
}
-void nbc_close (nbc_t *this) {
-#ifdef LOG
- printf("net_buf_ctrl: nbc_close\n");
-#endif
- this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
- free (this);
-}
+/* Get callback
+ * the fifo mutex is locked */
+void nbc_get_cb (fifo_buffer_t *fifo, buf_element_t *buf, void *this_gen) {
+ nbc_t *this = (nbc_t*)this_gen;
+ int other_fifo_free;
+ pthread_mutex_lock(&this->mutex);
-void nbc_end_of_stream (nbc_t *this) {
-#ifdef LOG
- printf("net_buf_ctrl: nbc_end_of_stream\n");
-#endif
- /* unpause the engine */
- if (this->buffering) {
- this->buffering = 0;
- this->stream->xine->clock->set_speed (this->stream->xine->clock, XINE_SPEED_NORMAL);
- this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
- if (this->stream->audio_out)
- this->stream->audio_out->set_property(this->stream->audio_out,AO_PROP_PAUSED,0);
+ nbc_compute_fifo_length(this, fifo, buf, FIFO_GET);
+
+ if (!this->enabled) {
+ display_stats(this);
+ pthread_mutex_unlock(&this->mutex);
+ return;
}
+
+ if (!this->buffering) {
+
+ /* start buffering if one fifo is empty */
+ if (fifo->fifo_size == 0) {
+ if (fifo == this->video_fifo) {
+ other_fifo_free = this->audio_fifo_free;
+ } else {
+ other_fifo_free = this->video_fifo_free;
+ }
+
+ /* Don't pause if the other fifo is full because the next
+ put() will restart the engine */
+ if (other_fifo_free > 1) {
+ this->buffering = 1;
+ this->progress = 0;
+ report_progress (this->stream, 0);
+
+ if (this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ printf("\nnet_buf_ctrl: nbc_put_cb: starts buffering\n");
+ nbc_set_speed_pause(this->stream);
+ }
+ }
+ } else {
+ nbc_set_speed_pause(this->stream);
+ }
+ display_stats(this);
+ pthread_mutex_unlock(&this->mutex);
}
nbc_t *nbc_init (xine_stream_t *stream) {
nbc_t *this = (nbc_t *) malloc (sizeof (nbc_t));
+ fifo_buffer_t *video_fifo = stream->video_fifo;
+ fifo_buffer_t *audio_fifo = stream->audio_fifo;
- this->stream = stream;
- this->buffering = 0;
- this->low_water_mark = DEFAULT_LOW_WATER_MARK;
- this->high_water_mark = DEFAULT_HIGH_WATER_MARK;
- this->progress = 0;
+#ifdef LOG
+ printf("net_buf_ctrl: nbc_init\n");
+#endif
+ pthread_mutex_init (&this->mutex, NULL);
+
+ this->stream = stream;
+ this->buffering = 0;
+ this->enabled = 0;
+ this->low_water_mark = DEFAULT_LOW_WATER_MARK;
+ this->high_water_mark = DEFAULT_HIGH_WATER_MARK;
+ this->progress = 0;
+ this->video_fifo = video_fifo;
+ this->audio_fifo = audio_fifo;
+ this->video_fifo_fill = 0;
+ this->audio_fifo_fill = 0;
+ this->video_fifo_free = 0;
+ this->audio_fifo_free = 0;
+ this->video_fifo_length = 0;
+ this->audio_fifo_length = 0;
+ this->video_last_pts = 0;
+ this->audio_last_pts = 0;
+ this->video_first_pts = 0;
+ this->audio_first_pts = 0;
+ this->video_fifo_size = 0;
+ this->audio_fifo_size = 0;
+ this->video_br = 0;
+ this->audio_br = 0;
+
+ video_fifo->register_put_cb(video_fifo, nbc_put_cb, this);
+ video_fifo->register_get_cb(video_fifo, nbc_get_cb, this);
+
+ if (audio_fifo) {
+ audio_fifo->register_put_cb(audio_fifo, nbc_put_cb, this);
+ audio_fifo->register_get_cb(audio_fifo, nbc_get_cb, this);
+ }
return this;
}
@@ -232,12 +457,14 @@ nbc_t *nbc_init (xine_stream_t *stream) {
void nbc_set_high_water_mark(nbc_t *this, int value) {
/*
+ Deprecated
this->high_water_mark = value;
*/
}
void nbc_set_low_water_mark(nbc_t *this, int value) {
/*
+ Deprecated
this->low_water_mark = value;
*/
}
diff --git a/src/xine-engine/buffer.c b/src/xine-engine/buffer.c
index af2f08242..7c3a94bf5 100644
--- a/src/xine-engine/buffer.c
+++ b/src/xine-engine/buffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2002 the xine project
+ * Copyright (C) 2000-2003 the xine project
*
* This file is part of xine, a free video player.
*
@@ -12,12 +12,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: buffer.c,v 1.26 2003/03/03 07:37:23 esnel Exp $
+ * $Id: buffer.c,v 1.27 2003/03/30 15:19:46 tmattern Exp $
*
*
* contents:
@@ -65,7 +65,7 @@ static void buffer_pool_free (buf_element_t *element) {
*/
static buf_element_t *buffer_pool_alloc (fifo_buffer_t *this) {
-
+
buf_element_t *buf;
pthread_mutex_lock (&this->buffer_pool_mutex);
@@ -109,9 +109,9 @@ static buf_element_t *buffer_pool_try_alloc (fifo_buffer_t *this) {
this->buffer_pool_num_free--;
} else {
-
+
buf = NULL;
-
+
}
pthread_mutex_unlock (&this->buffer_pool_mutex);
@@ -132,12 +132,15 @@ static buf_element_t *buffer_pool_try_alloc (fifo_buffer_t *this) {
* append buffer element to fifo buffer
*/
static void fifo_buffer_put (fifo_buffer_t *fifo, buf_element_t *element) {
-
+
pthread_mutex_lock (&fifo->mutex);
- if (fifo->last)
+ if (fifo->put_cb)
+ fifo->put_cb(fifo, element, fifo->put_cb_data);
+
+ if (fifo->last)
fifo->last->next = element;
- else
+ else
fifo->first = element;
fifo->last = element;
@@ -154,15 +157,15 @@ static void fifo_buffer_put (fifo_buffer_t *fifo, buf_element_t *element) {
* insert buffer element to fifo buffer (demuxers MUST NOT call this one)
*/
static void fifo_buffer_insert (fifo_buffer_t *fifo, buf_element_t *element) {
-
+
pthread_mutex_lock (&fifo->mutex);
element->next = fifo->first;
fifo->first = element;
-
+
if( !fifo->last )
fifo->last = element;
-
+
fifo->fifo_size++;
fifo->fifo_data_size += element->size;
@@ -194,6 +197,9 @@ static buf_element_t *fifo_buffer_get (fifo_buffer_t *fifo) {
fifo->fifo_size--;
fifo->fifo_data_size -= buf->size;
+ if (fifo->get_cb)
+ fifo->get_cb(fifo, buf, fifo->get_cb_data);
+
pthread_mutex_unlock (&fifo->mutex);
return buf;
@@ -227,6 +233,7 @@ static void fifo_buffer_clear (fifo_buffer_t *fifo) {
fifo->last = prev;
fifo->fifo_size--;
+ fifo->fifo_data_size -= buf->size;
buf->free_buffer(buf);
} else
@@ -318,6 +325,34 @@ static void fifo_buffer_dispose (fifo_buffer_t *this) {
}
/*
+ * Register a "put" callback
+ */
+static void fifo_register_put_cb (fifo_buffer_t *this,
+ void (*cb)(fifo_buffer_t *this,
+ buf_element_t *buf,
+ void *data_cb),
+ void *data_cb) {
+ pthread_mutex_lock(&this->mutex);
+ this->put_cb = cb;
+ this->put_cb_data = data_cb;
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/*
+ * Register a "get" callback
+ */
+static void fifo_register_get_cb (fifo_buffer_t *this,
+ void (*cb)(fifo_buffer_t *this,
+ buf_element_t *buf,
+ void *data_cb),
+ void *data_cb) {
+ pthread_mutex_lock(&this->mutex);
+ this->get_cb = cb;
+ this->get_cb_data = data_cb;
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/*
* allocate and initialize new (empty) fifo buffer
*/
fifo_buffer_t *fifo_buffer_new (int num_buffers, uint32_t buf_size) {
@@ -340,7 +375,8 @@ fifo_buffer_t *fifo_buffer_new (int num_buffers, uint32_t buf_size) {
this->num_free = fifo_buffer_num_free;
this->data_size = fifo_buffer_data_size;
this->dispose = fifo_buffer_dispose;
-
+ this->register_get_cb = fifo_register_get_cb;
+ this->register_put_cb = fifo_register_put_cb;
pthread_mutex_init (&this->mutex, NULL);
pthread_cond_init (&this->not_empty, NULL);
@@ -384,7 +420,10 @@ fifo_buffer_t *fifo_buffer_new (int num_buffers, uint32_t buf_size) {
this->buffer_pool_buf_size = buf_size;
this->buffer_pool_alloc = buffer_pool_alloc;
this->buffer_pool_try_alloc = buffer_pool_try_alloc;
-
+ this->get_cb = NULL;
+ this->put_cb = NULL;
+ this->get_cb_data = NULL;
+ this->put_cb_data = NULL;
return this;
}
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index a1d9073df..98d8bb67a 100644
--- a/src/xine-engine/buffer.h
+++ b/src/xine-engine/buffer.h
@@ -12,12 +12,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: buffer.h,v 1.105 2003/03/23 17:12:30 holstsn Exp $
+ * $Id: buffer.h,v 1.106 2003/03/30 15:19:46 tmattern Exp $
*
*
* contents:
@@ -158,7 +158,7 @@ extern "C" {
#define BUF_AUDIO_DTS 0x03050000
#define BUF_AUDIO_MSADPCM 0x03060000
#define BUF_AUDIO_MSIMAADPCM 0x03070000
-#define BUF_AUDIO_MSGSM 0x03080000
+#define BUF_AUDIO_MSGSM 0x03080000
#define BUF_AUDIO_VORBIS 0x03090000
#define BUF_AUDIO_IMC 0x030a0000
#define BUF_AUDIO_LH 0x030b0000
@@ -199,7 +199,7 @@ extern "C" {
#define BUF_AUDIO_WMAV 0x032E0000
/* spu buffer types: */
-
+
#define BUF_SPU_BASE 0x04000000
#define BUF_SPU_DVD 0x04000000
#define BUF_SPU_TEXT 0x04010000
@@ -226,7 +226,7 @@ struct buf_element_s {
unsigned char *content; /* start of raw content in mem (without header etc) */
int32_t size ; /* size of _content_ */
- int32_t max_size; /* size of pre-allocated memory pointed to by "mem" */
+ int32_t max_size; /* size of pre-allocated memory pointed to by "mem" */
uint32_t type;
int64_t pts; /* presentation time stamp, used for a/v sync */
int64_t disc_off; /* discontinuity offset */
@@ -443,10 +443,12 @@ struct fifo_buffer_s
/* the same as put but insert at the head of the fifo */
void (*insert) (fifo_buffer_t *fifo, buf_element_t *buf);
+ void (*register_put_cb) (fifo_buffer_t *fifo, void (*cb)(fifo_buffer_t *fifo, buf_element_t *buf, void *), void *cb_data);
+ void (*register_get_cb) (fifo_buffer_t *fifo, void (*cb)(fifo_buffer_t *fifo, buf_element_t *buf, void *), void *cb_data);
+
/*
* private variables for buffer pool management
*/
-
buf_element_t *buffer_pool_top; /* a stack actually */
pthread_mutex_t buffer_pool_mutex;
pthread_cond_t buffer_pool_cond_not_empty;
@@ -454,6 +456,10 @@ struct fifo_buffer_s
int buffer_pool_capacity;
int buffer_pool_buf_size;
void *buffer_pool_base; /*used to free mem chunk */
+ void (*put_cb)(fifo_buffer_t *fifo, buf_element_t *buf, void *data_cb);
+ void (*get_cb)(fifo_buffer_t *fifo, buf_element_t *buf, void *data_cb);
+ void *put_cb_data;
+ void *get_cb_data;
} ;
/*
diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c
index 1edfac777..88c5515f5 100644
--- a/src/xine-engine/demux.c
+++ b/src/xine-engine/demux.c
@@ -160,7 +160,7 @@ void xine_demux_control_start( xine_stream_t *stream ) {
void xine_demux_control_end( xine_stream_t *stream, uint32_t flags ) {
buf_element_t *buf;
-
+
buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo);
buf->type = BUF_CONTROL_END;
buf->decoder_flags = flags;
@@ -174,15 +174,32 @@ void xine_demux_control_end( xine_stream_t *stream, uint32_t flags ) {
}
}
+void xine_demux_control_nop( xine_stream_t *stream, uint32_t flags ) {
+
+ buf_element_t *buf;
+
+ buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo);
+ buf->type = BUF_CONTROL_NOP;
+ buf->decoder_flags = flags;
+ stream->video_fifo->put (stream->video_fifo, buf);
+
+ if (stream->audio_fifo) {
+ buf = stream->audio_fifo->buffer_pool_alloc (stream->audio_fifo);
+ buf->type = BUF_CONTROL_NOP;
+ buf->decoder_flags = flags;
+ stream->audio_fifo->put (stream->audio_fifo, buf);
+ }
+}
+
static void *demux_loop (void *stream_gen) {
xine_stream_t *stream = (xine_stream_t *)stream_gen;
int status;
-
+
#ifdef LOG
printf ("demux: loop starting...\n");
#endif
-
+
pthread_mutex_lock( &stream->demux_lock );
/* do-while needed to seek after demux finished */
@@ -208,13 +225,9 @@ static void *demux_loop (void *stream_gen) {
#ifdef LOG
printf ("demux: main demuxer loop finished (status: %d)\n", status);
#endif
- /* Avoid deadlock with net_buf_ctrl */
- stream->xine->clock->set_speed (stream->xine->clock, XINE_SPEED_NORMAL);
- stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
- if (stream->audio_out)
- stream->audio_out->set_property(stream->audio_out,AO_PROP_PAUSED,0);
/* wait before sending end buffers: user might want to do a new seek */
+ xine_demux_control_nop(stream, BUF_FLAG_END_STREAM);
while(stream->demux_thread_running &&
((!stream->video_fifo || stream->video_fifo->size(stream->video_fifo)) ||
(stream->audio_out
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 144789039..c927eb162 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: xine.c,v 1.239 2003/03/27 18:57:10 miguelfreitas Exp $
+ * $Id: xine.c,v 1.240 2003/03/30 15:19:46 tmattern Exp $
*
* top-level xine functions
*
@@ -782,11 +782,11 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
free(config_entry);
}
}
-
+
}
if (!stream->demux_plugin) {
-
+
/*
* find a demux plugin
*/
@@ -796,6 +796,10 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
stream->status = XINE_STATUS_STOP;
+
+ /* force the engine to unregister fifo callbacks */
+ xine_demux_control_nop(stream, BUF_FLAG_END_STREAM);
+
return 0;
}
@@ -807,7 +811,7 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
= strdup (stream->demux_plugin->demux_class->get_identifier(stream->demux_plugin->demux_class));
}
- xine_log (stream->xine, XINE_LOG_MSG,
+ xine_log (stream->xine, XINE_LOG_MSG,
"xine: found demuxer plugin: %s\n",
stream->demux_plugin->demux_class->get_description(stream->demux_plugin->demux_class));
@@ -820,7 +824,7 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
*/
stream->stream_info[XINE_STREAM_INFO_VIDEO_HANDLED] = 1;
stream->stream_info[XINE_STREAM_INFO_AUDIO_HANDLED] = 1;
-
+
/*
* send and decode headers
*/
@@ -834,7 +838,7 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
stream->demux_plugin->dispose (stream->demux_plugin);
stream->demux_plugin = NULL;
- if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
printf ("xine: demux disposed\n");
stream->input_plugin->dispose (stream->input_plugin);
@@ -846,15 +850,15 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
/*if (stream->audio_out)
stream->audio_out->control (stream->audio_out, AO_CTRL_FLUSH_BUFFERS);
*/
-
+
stream->status = XINE_STATUS_STOP;
- if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
printf ("xine: return from xine_open_internal\n");
return 0;
}
-
+
xine_demux_control_headers_done (stream);
#ifdef LOG
@@ -874,7 +878,7 @@ int xine_open (xine_stream_t *stream, const char *mrl) {
#endif
ret = xine_open_internal (stream, mrl);
-
+
pthread_mutex_unlock (&stream->frontend_lock);
return ret;
@@ -887,10 +891,10 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t
off_t pos, len;
int demux_status;
- if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
printf ("xine: xine_play\n");
- if (stream->xine->clock->speed != XINE_SPEED_NORMAL)
+ if (stream->xine->clock->speed != XINE_SPEED_NORMAL)
xine_set_speed_internal (stream, XINE_SPEED_NORMAL);
/* Wait until the first frame produced by the previous
@@ -917,21 +921,21 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t
len = stream->current_extra_info->input_length;
pthread_mutex_unlock( &stream->current_extra_info_lock );
/* FIXME: do we need to protect concurrent access to input plugin here? */
- if ((len == 0) && stream->input_plugin)
+ if ((len == 0) && stream->input_plugin)
len = stream->input_plugin->get_length (stream->input_plugin);
share = (double) start_pos / 65535;
pos = (off_t) (share * len) ;
} else
pos = 0;
-
+
if (!stream->demux_plugin) {
- xine_log (stream->xine, XINE_LOG_MSG,
+ xine_log (stream->xine, XINE_LOG_MSG,
_("xine_play: no demux available\n"));
stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
-
+
return 0;
- }
-
+ }
+
stream->demux_action_pending = 1;
pthread_mutex_lock( &stream->demux_lock );
demux_status = stream->demux_plugin->seek (stream->demux_plugin,
@@ -940,18 +944,18 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t
pthread_mutex_unlock( &stream->demux_lock );
if (demux_status != DEMUX_OK) {
- xine_log (stream->xine, XINE_LOG_MSG,
+ xine_log (stream->xine, XINE_LOG_MSG,
_("xine_play: demux failed to start\n"));
-
+
stream->err = XINE_ERROR_DEMUX_FAILED;
-
+
return 0;
-
+
} else {
xine_demux_start_thread( stream );
stream->status = XINE_STATUS_PLAY;
}
-
+
pthread_mutex_lock (&stream->first_frame_lock);
stream->first_frame_flag = 1;
pthread_mutex_unlock (&stream->first_frame_lock);
@@ -959,11 +963,11 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t
extra_info_reset( stream->current_extra_info );
pthread_mutex_unlock( &stream->current_extra_info_lock );
- if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
printf ("xine: xine_play_internal ...done\n");
return 1;
-}
+}
int xine_play (xine_stream_t *stream, int start_pos, int start_time) {
@@ -1004,7 +1008,7 @@ int xine_eject (xine_stream_t *stream) {
void xine_dispose (xine_stream_t *stream) {
- if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
printf ("xine: xine_dispose\n");
stream->status = XINE_STATUS_QUIT;
@@ -1315,7 +1319,7 @@ static int xine_get_stream_length (xine_stream_t *stream) {
return 0;
}
-int xine_get_pos_length (xine_stream_t *stream, int *pos_stream,
+int xine_get_pos_length (xine_stream_t *stream, int *pos_stream,
int *pos_time, int *length_time) {
int pos = xine_get_current_position (stream); /* force updating extra_info */