diff options
author | Thibaut Mattern <tmattern@users.sourceforge.net> | 2004-10-14 23:25:24 +0000 |
---|---|---|
committer | Thibaut Mattern <tmattern@users.sourceforge.net> | 2004-10-14 23:25:24 +0000 |
commit | 0afc766174a39031fa27686bba32e28dd87af09c (patch) | |
tree | a08f81e534bf1550f66dce996180ac9cfd5ed573 | |
parent | 54ef2ac454dab005c5a6a808b2c5bbcdfe544b8f (diff) | |
download | xine-lib-0afc766174a39031fa27686bba32e28dd87af09c.tar.gz xine-lib-0afc766174a39031fa27686bba32e28dd87af09c.tar.bz2 |
Implemented stream_t reference counter idea.
See these two threads:
http://thread.gmane.org/gmane.comp.video.xine.devel/10819
http://thread.gmane.org/gmane.comp.video.xine.devel/10424
Fixed _x_handle_stream_end __stop_internal race.
See this thread:
http://thread.gmane.org/gmane.comp.video.xine.devel/10818
If the lib is broken after this patch, you know who to blame ;-)
CVS patchset: 7036
CVS date: 2004/10/14 23:25:24
-rw-r--r-- | src/xine-engine/Makefile.am | 4 | ||||
-rw-r--r-- | src/xine-engine/audio_decoder.c | 7 | ||||
-rw-r--r-- | src/xine-engine/demux.c | 49 | ||||
-rw-r--r-- | src/xine-engine/refcounter.c | 77 | ||||
-rw-r--r-- | src/xine-engine/refcounter.h | 49 | ||||
-rw-r--r-- | src/xine-engine/video_decoder.c | 5 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 9 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 128 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 6 |
9 files changed, 233 insertions, 101 deletions
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index 696a501b6..ac4d3e2f5 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -25,7 +25,7 @@ libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c \ audio_decoder.c video_out.c audio_out.c resample.c events.c \ video_overlay.c osd.c scratch.c demux.c vo_scale.c \ xine_interface.c post.c tvmode.c broadcaster.c io_helper.c \ - input_rip.c info_helper.c + input_rip.c info_helper.c refcounter.c # FIXME: these are currently unused: EXTRA_DIST = lrb.c lrb.h accel_xvmc.h @@ -45,7 +45,7 @@ include_HEADERS = buffer.h metronom.h configfile.h vo_scale.h \ audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \ video_overlay.h osd.h scratch.h xine_plugin.h xineintl.h \ plugin_catalog.h audio_decoder.h video_decoder.h post.h \ - io_helper.h broadcaster.h info_helper.h + io_helper.h broadcaster.h info_helper.h refcounter.h noinst_HEADERS = bswap.h diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index b69908384..f48a5a35c 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.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: audio_decoder.c,v 1.129 2004/07/06 22:53:22 miguelfreitas Exp $ + * $Id: audio_decoder.c,v 1.130 2004/10/14 23:25:24 tmattern Exp $ * * * functions that implement audio decoding @@ -162,11 +162,6 @@ static void *audio_decoder_loop (void *stream_gen) { pthread_mutex_unlock (&stream->counter_lock); stream->audio_channel_auto = -1; - if (!stream->video_thread) { - /* set engine status, send frontend notification event */ - _x_handle_stream_end (stream, buf->decoder_flags & BUF_FLAG_END_STREAM); - } - break; case BUF_CONTROL_QUIT: diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c index d01e2a887..4e56a5256 100644 --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -20,7 +20,7 @@ * Demuxer helper functions * hide some xine engine details from demuxers and reduce code duplication * - * $Id: demux.c,v 1.50 2004/06/13 21:28:57 miguelfreitas Exp $ + * $Id: demux.c,v 1.51 2004/10/14 23:25:24 tmattern Exp $ */ @@ -160,8 +160,8 @@ void _x_demux_control_headers_done (xine_stream_t *stream) { buf->type = BUF_CONTROL_HEADERS_DONE; stream->audio_fifo->put (stream->audio_fifo, buf); - while ((stream->header_count_audio<header_count_audio) || - (stream->header_count_video<header_count_video)) { + while ((stream->header_count_audio < header_count_audio) || + (stream->header_count_video < header_count_video)) { struct timeval tv; struct timespec ts; @@ -230,6 +230,9 @@ static void *demux_loop (void *stream_gen) { xine_stream_t *stream = (xine_stream_t *)stream_gen; int status; + int finished_count_audio = 0; + int finished_count_video = 0; + int non_user; lprintf ("loop starting...\n"); @@ -277,19 +280,32 @@ static void *demux_loop (void *stream_gen) { lprintf ("loop finished (status: %d)\n", status); - /* demux_thread_running is zero if demux loop has being stopped by user */ - if (stream->demux_thread_running) { - _x_demux_control_end(stream, BUF_FLAG_END_STREAM); - } else { - _x_demux_control_end(stream, BUF_FLAG_END_USER); - } + pthread_mutex_lock (&stream->counter_lock); + if (stream->audio_thread) + finished_count_audio = stream->finished_count_audio + 1; + if (stream->video_thread) + finished_count_video = stream->finished_count_video + 1; + pthread_mutex_unlock (&stream->counter_lock); + + _x_demux_control_end(stream, 0); lprintf ("loop finished, end buffer sent\n"); + /* demux_thread_running is zero if demux loop has being stopped by user */ + non_user = stream->demux_thread_running; stream->demux_thread_running = 0; - pthread_mutex_unlock( &stream->demux_lock ); + pthread_mutex_lock (&stream->counter_lock); + while ((stream->finished_count_audio < finished_count_audio) || + (stream->finished_count_video < finished_count_video)) { + lprintf ("waiting for finisheds.\n"); + pthread_cond_wait (&stream->counter_changed, &stream->counter_lock); + } + pthread_mutex_unlock (&stream->counter_lock); + + _x_handle_stream_end(stream, non_user); + stream->demux_thread = 0; return NULL; } @@ -327,21 +343,18 @@ int _x_demux_stop_thread (xine_stream_t *stream) { pthread_mutex_lock( &stream->demux_lock ); stream->demux_thread_running = 0; stream->demux_action_pending = 0; + + /* At that point, the demuxer has sent the last audio/video buffer, + * so it's a safe place to flush the engine. + */ + _x_demux_flush_engine( stream ); pthread_mutex_unlock( &stream->demux_lock ); lprintf ("joining thread %ld\n", stream->demux_thread ); - /* FIXME: counter_lock isn't meant to protect demux_thread update. - however we can't use demux_lock here. should we create a new lock? */ - pthread_mutex_lock (&stream->counter_lock); - - /* <join; demux_thread = 0;> must be atomic */ if( stream->demux_thread ) pthread_join (stream->demux_thread, &p); - stream->demux_thread = 0; - pthread_mutex_unlock (&stream->counter_lock); - /* * Wake up xine_play if it's waiting for a frame */ diff --git a/src/xine-engine/refcounter.c b/src/xine-engine/refcounter.c new file mode 100644 index 000000000..11c6ceb11 --- /dev/null +++ b/src/xine-engine/refcounter.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: refcounter.c,v 1.1 2004/10/14 23:25:24 tmattern Exp $ + * + */ +#define LOG_MODULE "refcounter" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "refcounter.h" +#include "xine_internal.h" + +refcounter_t* _x_new_refcounter(void *object, void (*destructor)(void *)) +{ + refcounter_t *new_refcounter; + + new_refcounter = (refcounter_t *) xine_xmalloc (sizeof (refcounter_t)); + new_refcounter->count = 1; + new_refcounter->object = object; + new_refcounter->destructor = destructor; + pthread_mutex_init (&new_refcounter->lock, NULL); + lprintf("new referenced object %p\n", object); + return new_refcounter; +} + +int _x_refcounter_inc(refcounter_t *refcounter) +{ + int res; + + pthread_mutex_lock(&refcounter->lock); + if (!refcounter->count) + _x_abort(); + res = ++refcounter->count; + pthread_mutex_unlock(&refcounter->lock); + + return res; +} + +int _x_refcounter_dec(refcounter_t *refcounter) +{ + int res; + + pthread_mutex_lock(&refcounter->lock); + res = --refcounter->count; + pthread_mutex_unlock(&refcounter->lock); + if (!res) { + lprintf("calling destructor of object %p\n", refcounter->object); + refcounter->destructor(refcounter->object); + } + + return res; +} + +void _x_refcounter_dispose(refcounter_t *refcounter) +{ + pthread_mutex_destroy (&refcounter->lock); + free(refcounter); +} diff --git a/src/xine-engine/refcounter.h b/src/xine-engine/refcounter.h new file mode 100644 index 000000000..98a9f26ae --- /dev/null +++ b/src/xine-engine/refcounter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: refcounter.h,v 1.1 2004/10/14 23:25:24 tmattern Exp $ + * + */ +#ifndef HAVE_REFCOUNTER_H +#define HAVE_REFCOUNTER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> + +typedef struct { + pthread_mutex_t lock; + int count; + void* object; /* referenced object */ + void (*destructor)(void *); /* object destructor */ +} refcounter_t; + +typedef void (*refcounter_destructor)(void*); + +refcounter_t* _x_new_refcounter(void *object, refcounter_destructor destructor); + +int _x_refcounter_inc(refcounter_t *refcounter); + +int _x_refcounter_dec(refcounter_t *refcounter); + +void _x_refcounter_dispose(refcounter_t *refcounter); + +#endif /* HAVE_REFCOUNTER_H */ diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index 9e2fa3af1..5a7a16ede 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.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: video_decoder.c,v 1.150 2004/07/06 22:53:23 miguelfreitas Exp $ + * $Id: video_decoder.c,v 1.151 2004/10/14 23:25:24 tmattern Exp $ * */ @@ -234,9 +234,6 @@ static void *video_decoder_loop (void *stream_gen) { pthread_cond_broadcast(&stream->first_frame_reached); } pthread_mutex_unlock (&stream->first_frame_lock); - - /* set engine status, send frontend notification event */ - _x_handle_stream_end (stream, buf->decoder_flags & BUF_FLAG_END_STREAM); break; case BUF_CONTROL_QUIT: diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 5495a029f..3deca0760 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.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: video_out.c,v 1.209 2004/10/09 06:44:21 mroi Exp $ + * $Id: video_out.c,v 1.210 2004/10/14 23:25:24 tmattern Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -246,6 +246,8 @@ static void vo_frame_dec_lock (vo_frame_t *img) { img->lock_counter--; if (!img->lock_counter) { vos_t *this = (vos_t *) img->port; + if (img->stream) + _x_refcounter_dec(img->stream->refcounter); vo_append_to_img_buf_queue (this->free_img_buf_queue, img); } @@ -335,6 +337,7 @@ static vo_frame_t *vo_get_frame (xine_video_port_t *this_gen, img->crop_right = 0; img->crop_top = 0; img->crop_bottom = 0; + img->stream = NULL; _x_extra_info_reset ( img->extra_info ); @@ -367,6 +370,7 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) { this->current_height = img->height; if (stream) { + _x_refcounter_inc(stream->refcounter); _x_extra_info_merge( img->extra_info, stream->video_decoder_extra_info ); stream->metronom->got_video_frame (stream->metronom, img); } @@ -660,7 +664,7 @@ static vo_frame_t * duplicate_frame( vos_t *this, vo_frame_t *img ) { dupl->duration = img->duration; dupl->is_first = img->is_first; - dupl->stream = img->stream; + dupl->stream = NULL; memcpy( dupl->extra_info, img->extra_info, sizeof(extra_info_t) ); /* delay frame processing for now, we might not even need it (eg. frame will be discarded) */ @@ -1599,6 +1603,7 @@ static vo_frame_t * crop_frame( xine_video_port_t *this_gen, vo_frame_t *img ) { dupl->is_first = img->is_first; dupl->stream = img->stream; + _x_refcounter_inc(img->stream->refcounter); memcpy( dupl->extra_info, img->extra_info, sizeof(extra_info_t) ); /* delay frame processing for now, we might not even need it (eg. frame will be discarded) */ diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 19d911301..7432bff60 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.297 2004/08/30 07:37:42 f1rmb Exp $ + * $Id: xine.c,v 1.298 2004/10/14 23:25:24 tmattern Exp $ */ /* @@ -48,9 +48,9 @@ #define LOG_MODULE "xine" #define LOG_VERBOSE -/* + #define LOG -*/ + #define XINE_ENABLE_EXPERIMENTAL_FEATURES #define XINE_ENGINE_INTERNAL @@ -83,9 +83,6 @@ void _x_handle_stream_end (xine_stream_t *stream, int non_user) { return; stream->status = XINE_STATUS_STOP; - /* join thread if needed to fix resource leaks */ - _x_demux_stop_thread( stream ); - if (non_user) { /* frontends will not be interested in receiving this event * if they have called xine_stop explicitly, so only send @@ -274,9 +271,6 @@ static void __set_speed_internal (xine_stream_t *stream, int speed) { /* stream->ignore_speed_change must be set, when entering this function */ static void __stop_internal (xine_stream_t *stream) { - int finished_count_audio = 0; - int finished_count_video = 0; - lprintf ("status before = %d\n", stream->status); if (stream->status == XINE_STATUS_STOP) { @@ -294,43 +288,10 @@ static void __stop_internal (xine_stream_t *stream) { /* * stop demux */ - - pthread_mutex_lock (&stream->counter_lock); - if (stream->audio_thread) - finished_count_audio = stream->finished_count_audio + 1; - else - finished_count_audio = 0; - - if (stream->video_thread) - finished_count_video = stream->finished_count_video + 1; - else - finished_count_video = 0; - - pthread_mutex_unlock (&stream->counter_lock); - lprintf ("stopping demux\n"); if (stream->demux_plugin) { - _x_demux_stop_thread( stream ); lprintf ("stop thread done\n"); - - _x_demux_flush_engine( stream ); - lprintf ("flush engine done\n"); - - /* - * wait until engine has really stopped - */ - -#if 0 - pthread_mutex_lock (&stream->counter_lock); - while ((stream->finished_count_audio<finished_count_audio) || - (stream->finished_count_video<finished_count_video)) { - - lprintf ("waiting for finisheds.\n"); - pthread_cond_wait (&stream->counter_changed, &stream->counter_lock); - } - pthread_mutex_unlock (&stream->counter_lock); -#endif } lprintf ("demux stopped\n"); lprintf ("done\n"); @@ -379,7 +340,21 @@ static void __close_internal (xine_stream_t *stream) { } stream->ignore_speed_change = 1; + stream->xine->port_ticket->acquire(stream->xine->port_ticket, 1); + + if (stream->audio_out) + stream->audio_out->set_property(stream->audio_out, AO_PROP_DISCARD_BUFFERS, 1); + if (stream->video_out) + stream->video_out->set_property(stream->video_out, VO_PROP_DISCARD_FRAMES, 1); + __stop_internal( stream ); + + if (stream->video_out) + stream->video_out->set_property(stream->video_out, VO_PROP_DISCARD_FRAMES, 0); + if (stream->audio_out) + stream->audio_out->set_property(stream->audio_out, AO_PROP_DISCARD_BUFFERS, 0); + + stream->xine->port_ticket->release(stream->xine->port_ticket, 1); stream->ignore_speed_change = 0; lprintf ("disposing demux\n"); @@ -466,6 +441,7 @@ static int __stream_rewire_video(xine_post_out_t *output, void *data) return 1; } +void __xine_dispose_internal (xine_stream_t *stream); xine_stream_t *xine_stream_new (xine_t *this, xine_audio_port_t *ao, xine_video_port_t *vo) { @@ -581,6 +557,11 @@ xine_stream_t *xine_stream_new (xine_t *this, stream->osd_renderer = _x_osd_renderer_init(stream); else stream->osd_renderer = NULL; + + /* + * create a reference counter + */ + stream->refcounter = _x_new_refcounter(stream, (refcounter_destructor)__xine_dispose_internal); /* * register stream @@ -1212,35 +1193,11 @@ int xine_eject (xine_stream_t *stream) { return status; } -void xine_dispose (xine_stream_t *stream) { +void __xine_dispose_internal (xine_stream_t *stream) { xine_stream_t *s; - xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "xine_dispose\n"); - - stream->status = XINE_STATUS_QUIT; - - xine_close(stream); - - if( stream->master != stream ) { - stream->master->slave = NULL; - } - if( stream->slave && stream->slave->master == stream ) { - stream->slave->master = NULL; - } - - if(stream->broadcaster) - _x_close_broadcaster(stream->broadcaster); - - xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "shutdown audio\n"); - _x_audio_decoder_shutdown (stream); - - xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "shutdown video\n"); - _x_video_decoder_shutdown (stream); - - if (stream->osd_renderer) - stream->osd_renderer->close( stream->osd_renderer ); - + lprintf("stream: %p\n", stream); pthread_mutex_destroy (&stream->info_mutex); pthread_mutex_destroy (&stream->meta_mutex); pthread_mutex_destroy (&stream->frontend_lock); @@ -1264,12 +1221,47 @@ void xine_dispose (xine_stream_t *stream) { } pthread_mutex_unlock(&stream->xine->streams_lock); + _x_refcounter_dispose(stream->refcounter); + free (stream->current_extra_info); free (stream->video_decoder_extra_info); free (stream->audio_decoder_extra_info); free (stream); } +void xine_dispose (xine_stream_t *stream) { + /* decrease the reference counter + * if there is no more reference on this stream, the __xine_dispose_internal + * function is called + */ + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "xine_dispose\n"); + stream->status = XINE_STATUS_QUIT; + + xine_close(stream); + + if( stream->master != stream ) { + stream->master->slave = NULL; + } + if( stream->slave && stream->slave->master == stream ) { + stream->slave->master = NULL; + } + + if(stream->broadcaster) + _x_close_broadcaster(stream->broadcaster); + + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "shutdown audio\n"); + _x_audio_decoder_shutdown (stream); + + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "shutdown video\n"); + _x_video_decoder_shutdown (stream); + + if (stream->osd_renderer) + stream->osd_renderer->close( stream->osd_renderer ); + + + _x_refcounter_dec(stream->refcounter); +} + void xine_exit (xine_t *this) { int i; diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 488df397b..2cdf53a2c 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -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_internal.h,v 1.160 2004/09/26 22:54:52 valtri Exp $ + * $Id: xine_internal.h,v 1.161 2004/10/14 23:25:24 tmattern Exp $ * */ @@ -34,6 +34,7 @@ extern "C" { #ifdef XINE_COMPILE # include "xine.h" +# include "refcounter.h" # include "input/input_plugin.h" # include "demuxers/demux.h" # include "video_out.h" @@ -51,6 +52,7 @@ extern "C" { # include "info_helper.h" #else # include <xine.h> +# include <xine/refcounter.h> # include <xine/input_plugin.h> # include <xine/demux.h> # include <xine/video_out.h> @@ -322,6 +324,8 @@ struct xine_stream_s { int err; broadcaster_t *broadcaster; + + refcounter_t *refcounter; #endif }; |