diff options
-rw-r--r-- | src/input/net_buf_ctrl.c | 493 | ||||
-rw-r--r-- | src/xine-engine/buffer.c | 67 | ||||
-rw-r--r-- | src/xine-engine/buffer.h | 18 | ||||
-rw-r--r-- | src/xine-engine/demux.c | 29 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 58 |
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 */ |