summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2001-12-24 00:45:03 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2001-12-24 00:45:03 +0000
commit52ed4de50d48141bda8f2300749ffa703b55be4b (patch)
tree260c92e7f7f28b59f65707025d23c2e1b558a5e1
parent2ff16582eef3e37548060b6863f4caa419bd4998 (diff)
downloadxine-lib-52ed4de50d48141bda8f2300749ffa703b55be4b.tar.gz
xine-lib-52ed4de50d48141bda8f2300749ffa703b55be4b.tar.bz2
automatic still image detection - based on miguel's work but with modifications to handle still images with audio, works pretty well on episode I, x-men and sleepy hollow and all other dvds I've tested
CVS patchset: 1294 CVS date: 2001/12/24 00:45:03
-rw-r--r--src/demuxers/demux_mpeg_block.c16
-rw-r--r--src/libmpeg2/decode.c21
-rw-r--r--src/libmpeg2/xine_decoder.c5
-rw-r--r--src/xine-engine/Makefile.am2
-rw-r--r--src/xine-engine/buffer.h3
-rw-r--r--src/xine-engine/metronom.c283
-rw-r--r--src/xine-engine/video_decoder.c38
-rw-r--r--src/xine-engine/video_out.c328
-rw-r--r--src/xine-engine/video_out.h19
-rw-r--r--src/xine-engine/xine.c4
-rw-r--r--src/xine-engine/xine_internal.h5
11 files changed, 485 insertions, 239 deletions
diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c
index 81b17d775..61993bf28 100644
--- a/src/demuxers/demux_mpeg_block.c
+++ b/src/demuxers/demux_mpeg_block.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: demux_mpeg_block.c,v 1.67 2001/12/01 22:38:31 guenter Exp $
+ * $Id: demux_mpeg_block.c,v 1.68 2001/12/24 00:45:03 guenter Exp $
*
* demultiplexer for mpeg 1/2 program streams
*
@@ -38,6 +38,10 @@
#include "xineutils.h"
#include "demux.h"
+/*
+#define LOG
+*/
+
#define VALID_MRLS "dvd,stdin,fifo"
#define VALID_ENDS "vob"
@@ -253,10 +257,20 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m
/* discontinuity ? */
{
int32_t scr_diff = scr - this->last_scr;
+
+#ifdef LOG
+ printf ("demux_mpeg_block: scr %d last_scr %d diff %d\n",
+ scr, this->last_scr, scr_diff);
+#endif
+
if (abs(scr_diff) > 60000) {
buf_element_t *buf;
+#ifdef LOG
+ printf ("demux_mpeg_block: DISCONTINUITY!\n");
+#endif
+
buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
buf->type = BUF_CONTROL_AVSYNC_RESET;
buf->SCR = scr;
diff --git a/src/libmpeg2/decode.c b/src/libmpeg2/decode.c
index 703b269e5..98cc87268 100644
--- a/src/libmpeg2/decode.c
+++ b/src/libmpeg2/decode.c
@@ -362,12 +362,26 @@ void mpeg2_flush (mpeg2dec_t * mpeg2dec) {
picture_t *picture = mpeg2dec->picture;
if (picture->backward_reference_frame && !picture->backward_reference_frame->drawn) {
+ vo_frame_t *img;
+
printf ("libmpeg2: blasting out backward reference frame on flush\n");
picture->backward_reference_frame->PTS = 0;
picture->backward_reference_frame->SCR = mpeg2dec->scr;
picture->backward_reference_frame->bad_frame = 0;
picture->backward_reference_frame->drawn = 1;
- picture->backward_reference_frame->draw (picture->backward_reference_frame);
+ picture->backward_reference_frame->displayed (picture->backward_reference_frame);
+
+ /* output a copy instead of the frame used by decoder */
+ img = picture->backward_reference_frame->instance->duplicate_frame(
+ picture->backward_reference_frame->instance,
+ picture->backward_reference_frame);
+ img->PTS = 0;
+ img->SCR = mpeg2dec->scr;
+ img->bad_frame = 0;
+ img->drawn = 2;
+ img->draw(img);
+
+ img->free(img);
}
}
@@ -407,12 +421,13 @@ void mpeg2_close (mpeg2dec_t * mpeg2dec)
picture->throwaway_frame->free (picture->throwaway_frame);
}
- if (picture->backward_reference_frame && !picture->backward_reference_frame->drawn) {
+ if (picture->backward_reference_frame) {
printf ("libmpeg2: blasting out backward reference frame on close\n");
picture->backward_reference_frame->PTS = 0;
picture->backward_reference_frame->SCR = mpeg2dec->scr;
picture->backward_reference_frame->bad_frame = 0;
- picture->backward_reference_frame->draw (picture->backward_reference_frame);
+ if( !picture->backward_reference_frame->drawn)
+ picture->backward_reference_frame->draw (picture->backward_reference_frame);
picture->backward_reference_frame->free (picture->backward_reference_frame);
}
diff --git a/src/libmpeg2/xine_decoder.c b/src/libmpeg2/xine_decoder.c
index 930562d39..da55cab88 100644
--- a/src/libmpeg2/xine_decoder.c
+++ b/src/libmpeg2/xine_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: xine_decoder.c,v 1.18 2001/12/11 15:30:06 miguelfreitas Exp $
+ * $Id: xine_decoder.c,v 1.19 2001/12/24 00:45:03 guenter Exp $
*
* stuff needed to turn libmpeg2 into a xine decoder plugin
*/
@@ -73,7 +73,8 @@ static void mpeg2dec_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
mpeg2_decode_data (&this->mpeg2, buf->content, buf->content + buf->size,
buf->PTS, buf->SCR);
-
+
+ this->video_out->decoder_started(this->video_out);
}
}
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am
index 00d270735..e52733df0 100644
--- a/src/xine-engine/Makefile.am
+++ b/src/xine-engine/Makefile.am
@@ -15,7 +15,7 @@ libxine_la_LIBADD = $(THREAD_LIBS) $(DYNAMIC_LD_LIBS) -lm -lz
libxine_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
- -release $(LT_RELEASE)
+ -release $(LT_RELEASE)
include_HEADERS = buffer.h metronom.h configfile.h \
audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index 480f1031e..0157c6a10 100644
--- a/src/xine-engine/buffer.h
+++ b/src/xine-engine/buffer.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: buffer.h,v 1.26 2001/12/01 22:38:32 guenter Exp $
+ * $Id: buffer.h,v 1.27 2001/12/24 00:45:03 guenter Exp $
*
*
* contents:
@@ -70,6 +70,7 @@ extern "C" {
#define BUF_CONTROL_AUDIO_CHANNEL 0x01050000
#define BUF_CONTROL_SPU_CHANNEL 0x01060000
#define BUF_CONTROL_AVSYNC_RESET 0x01070000
+#define BUF_CONTROL_FLUSH 0x01080000
/* video buffer types: (please keep in sync with buffer_types.c) */
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c
index 4b8bf85aa..4a18e7f35 100644
--- a/src/xine-engine/metronom.c
+++ b/src/xine-engine/metronom.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: metronom.c,v 1.43 2001/12/23 13:21:56 miguelfreitas Exp $
+ * $Id: metronom.c,v 1.44 2001/12/24 00:45:03 guenter Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -438,16 +438,21 @@ static void metronom_expect_video_discontinuity (metronom_t *this) {
pthread_mutex_lock (&this->lock);
- printf ("metronom: video discontinuity\n");
-
this->video_discontinuity = 10;
this->video_discontinuity_count++;
pthread_cond_signal (&this->video_discontinuity_reached);
+ printf ("metronom: video discontinuity #%d\n",
+ this->video_discontinuity_count);
+
if( this->have_audio ) {
while ( this->audio_discontinuity_count <
this->video_discontinuity_count ) {
+
+ printf ("metronom: waiting for audio discontinuity #%d\n",
+ this->video_discontinuity_count);
+
pthread_cond_wait (&this->audio_discontinuity_reached, &this->lock);
}
@@ -457,15 +462,13 @@ static void metronom_expect_video_discontinuity (metronom_t *this) {
}
}
- this->num_video_vpts_guessed = 0;
- this->last_video_pts = this->video_vpts - this->video_wrap_offset;
-
+ /* this->num_video_vpts_guessed = 0; */
+ /* this->last_video_pts = this->video_vpts - this->video_wrap_offset; */
+ /*
this->avg_frame_duration = this->pts_per_frame;
+ */
this->frames_since_start = 0;
- printf ("metronom: video discontinuity => last_video_pts=%d, wrap_offset=%d, video_vpts=%d\n",
- this->last_video_pts, this->video_wrap_offset, this->video_vpts);
-
pthread_mutex_unlock (&this->lock);
}
@@ -477,7 +480,7 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32
pthread_mutex_lock (&this->lock);
/* check for pts discontinuities against the predicted pts value */
- if( pts && this->last_video_pts ) {
+ if (pts && this->last_video_pts) {
vpts = this->last_video_pts +
(this->num_video_vpts_guessed+1) * this->avg_frame_duration;
if( ( pts > vpts && (pts - vpts) > WRAP_THRESHOLD ) ||
@@ -505,72 +508,74 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32
this->video_stream_starting = 0;
this->wrap_diff_counter = 0;
- this->video_wrap_offset += this->last_video_pts - pts
- + (this->num_video_vpts_guessed+1) * this->avg_frame_duration;
+ this->video_wrap_offset = this->video_vpts - pts ;
+ /* + this->num_video_vpts_guessed * this->avg_frame_duration; */
- printf ("metronom: video pts discontinuity, pts is %d, last_pts is %d, wrap_offset = %d\n",
- pts, this->last_video_pts, this->video_wrap_offset);
+ vpts = pts + this->video_wrap_offset;
- this->last_video_pts = 0;
- }
+ printf ("metronom: video pts discontinuity/start, pts is %d, wrap_offset is %d, vpts is %d\n",
+ pts, this->video_wrap_offset, vpts);
- /*
- * audio and video wrap are not allowed to differ for too long
- */
- if ( !this->audio_stream_starting && this->have_audio
- && (this->video_wrap_offset != this->audio_wrap_offset)
- && !this->video_discontinuity && !this->audio_discontinuity ) {
- this->wrap_diff_counter++;
-
- if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
-
- printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)",
- this->video_wrap_offset, this->audio_wrap_offset);
-
- if (this->video_wrap_offset > this->audio_wrap_offset)
- this->audio_wrap_offset = this->video_wrap_offset;
- else
- this->video_wrap_offset = this->audio_wrap_offset;
-
- printf (" to %d\n", this->video_wrap_offset);
+ } else {
- this->wrap_diff_counter = 0;
+ /*
+ * audio and video wrap are not allowed to differ for too long
+ */
+ if ( !this->audio_stream_starting && this->have_audio
+ && (this->video_wrap_offset != this->audio_wrap_offset)
+ && !this->video_discontinuity && !this->audio_discontinuity ) {
+ this->wrap_diff_counter++;
+
+ if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
+
+ printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)",
+ this->video_wrap_offset, this->audio_wrap_offset);
+
+ if (this->video_wrap_offset > this->audio_wrap_offset)
+ this->audio_wrap_offset = this->video_wrap_offset;
+ else
+ this->video_wrap_offset = this->audio_wrap_offset;
+
+ printf (" to %d\n", this->video_wrap_offset);
+
+ this->wrap_diff_counter = 0;
+ }
}
- }
-
- /*
- * calc overall average frame duration (according to pts values)
- */
- if (this->frames_since_start && this->last_video_pts) {
- int current_avg_delta;
-
- int weight_old = 9;
- int weight_new = 1;
/*
- printf("foo: pts %d, last pts %d\n", pts, this->last_video_pts);
- */
-
- if (pts > this->last_video_pts) {
- current_avg_delta = (pts - this->last_video_pts) / (this->num_video_vpts_guessed + 1);
-
- /*
- printf("foo: current_avg_delta %d\n", current_avg_delta);
- */
-
- this->avg_frame_duration =
- (((this->avg_frame_duration * weight_old) + (current_avg_delta * weight_new)) /
- (weight_old + weight_new));
- } else {
- current_avg_delta = (this->last_video_pts - pts) / (this->num_video_vpts_guessed + 1);
-
+ * calc overall average frame duration (according to pts values)
+ */
+ if (this->frames_since_start && this->last_video_pts) {
+ int current_avg_delta;
+
+ int weight_old = 9;
+ int weight_new = 1;
+
/*
- printf("foo: current_avg_delta - %d\n", current_avg_delta);
+ printf("foo: pts %d, last pts %d\n", pts, this->last_video_pts);
*/
-
- this->avg_frame_duration =
- (((this->avg_frame_duration * weight_old) - (current_avg_delta * weight_new)) /
+
+ if (pts > this->last_video_pts) {
+ current_avg_delta = (pts - this->last_video_pts) / (this->num_video_vpts_guessed + 1);
+
+ /*
+ printf("foo: current_avg_delta %d\n", current_avg_delta);
+ */
+
+ this->avg_frame_duration =
+ (((this->avg_frame_duration * weight_old) + (current_avg_delta * weight_new)) /
(weight_old + weight_new));
+ } else {
+ current_avg_delta = (this->last_video_pts - pts) / (this->num_video_vpts_guessed + 1);
+
+ /*
+ printf("foo: current_avg_delta - %d\n", current_avg_delta);
+ */
+
+ this->avg_frame_duration =
+ (((this->avg_frame_duration * weight_old) - (current_avg_delta * weight_new)) /
+ (weight_old + weight_new));
+ }
}
}
@@ -579,36 +584,38 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32
this->video_vpts += this->avg_frame_duration;
+ /*
+ * smoothen possibly wrong pts as long as delta is small
+ */
+
if (pts) {
int drift;
int delta = this->video_vpts - this->video_wrap_offset - pts;
#ifdef METRONOM_LOG
- printf("metronom: delta: %d\n", delta);
+ printf("metronom: delta (vpts <-> pts+wrap_offset): %d\n", delta);
#endif
- /* does xine need this ?!
- if (abs (delta) > 30000) {
+ if (abs (delta) > 45000) {
- discontinuity
-
- this->video_vpts = pts + this->this->video_wrap_offset;
+ this->video_vpts = pts + this->video_wrap_offset;
- printf ("metronom: disc. detected\n");
+ printf ("metronom: delta too big, setting vpts to %d\n",
+ this->video_vpts);
} else {
- */
-
- if (this->num_video_vpts_guessed > 10)
- this->num_video_vpts_guessed = 10;
- drift = delta / 20 * (this->num_video_vpts_guessed + 1);
+ if (this->num_video_vpts_guessed > 10)
+ this->num_video_vpts_guessed = 10;
+
+ drift = delta / 20 * (this->num_video_vpts_guessed + 1);
#ifdef METRONOM_LOG
- printf("metronom: compensating drift: %d\n", drift);
+ printf("metronom: compensation drift: %d\n", drift);
#endif
- this->video_vpts -= drift;
+ this->video_vpts -= drift;
+ }
this->num_video_vpts_guessed = 0;
} else
@@ -617,10 +624,8 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32
this->frames_since_start++;
#ifdef METRONOM_LOG
- printf("metronom: stats: %d num guessed, %d avg_frame_duration. %d frames since start\n",
- this->num_video_vpts_guessed, this->avg_frame_duration, this->frames_since_start);
-
- printf ("metronom: video vpts for %10d : %10d\n", pts, this->video_vpts);
+ printf ("metronom: video vpts for %10d : %10d (avg_frame_duration %d)\n",
+ pts, this->video_vpts, this->avg_frame_duration);
#endif
vpts = this->video_vpts + this->av_offset;
@@ -634,28 +639,30 @@ static void metronom_expect_audio_discontinuity (metronom_t *this) {
pthread_mutex_lock (&this->lock);
- printf ("metronom: audio discontinuity\n");
-
this->audio_discontinuity = 10;
this->audio_discontinuity_count++;
pthread_cond_signal (&this->audio_discontinuity_reached);
+ printf ("metronom: audio discontinuity #%d\n",
+ this->audio_discontinuity_count);
+
while ( this->audio_discontinuity_count >
this->video_discontinuity_count ) {
+
+ printf ("metronom: waiting for video_discontinuity #%d\n", this->audio_discontinuity_count);
+
pthread_cond_wait (&this->video_discontinuity_reached, &this->lock);
}
if ( this->audio_vpts < this->video_vpts ) {
- this->audio_vpts = this->video_vpts;
+ this->audio_wrap_offset += this->video_vpts - this->audio_vpts ;
+ this->audio_vpts = this->video_vpts;
printf("metronom: audio vpts adjusted to %d\n", this->audio_vpts);
}
- this->num_audio_samples_guessed = 1;
- this->last_audio_pts = this->audio_vpts - this->audio_wrap_offset;
+ /* this->num_audio_samples_guessed = 1; */
+ /* this->last_audio_pts = this->audio_vpts - this->audio_wrap_offset; */
- printf ("metronom: audio discontinuity => last_audio_pts=%d, wrap_offset=%d, audio_vpts=%d\n",
- this->last_audio_pts, this->audio_wrap_offset, this->audio_vpts);
-
pthread_mutex_unlock (&this->lock);
}
@@ -666,10 +673,8 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts,
uint32_t vpts;
#ifdef METRONOM_LOG
- printf ("metronom: DTS pts is %u, last_pts is %u, diff = %d\n",
- pts, this->last_audio_pts, pts - this->last_audio_pts);
- printf ("metronom: got %d audio samples (pts=%d)\n",
- nsamples,pts);
+ printf ("metronom: got %d samples, pts is %u, last_pts is %u, diff = %d\n",
+ nsamples, pts, this->last_audio_pts, pts - this->last_audio_pts);
#endif
pthread_mutex_lock (&this->lock);
@@ -687,56 +692,62 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts,
this->audio_stream_starting = 0;
this->wrap_diff_counter = 0;
- this->audio_wrap_offset += this->last_audio_pts - pts
+ this->audio_wrap_offset = this->audio_vpts - pts ;
+ /*
+ this->num_audio_samples_guessed
* (this->audio_pts_delta + this->pts_per_smpls) / AUDIO_SAMPLE_NUM ;
+ */
- printf ("metronom: audio pts discontinuity/start, pts is %d, last_pts is %d, wrap_offset = %d\n",
- pts, this->last_audio_pts, this->audio_wrap_offset);
-
- }
-
- /*
- * audio and video wrap are not allowed to differ
- * for too long
- */
-
- if ( this->video_wrap_offset != this->audio_wrap_offset
- && !this->video_discontinuity && !this->audio_discontinuity ) {
- this->wrap_diff_counter++;
-
- if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
+ vpts = pts + this->audio_wrap_offset;
- printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)",
- this->video_wrap_offset, this->audio_wrap_offset);
+ printf ("metronom: audio pts discontinuity/start, pts is %d, wrap_offset is %d, vpts is %d\n",
+ pts, this->audio_wrap_offset, vpts);
- if (this->video_wrap_offset > this->audio_wrap_offset)
- this->audio_wrap_offset = this->video_wrap_offset;
- else
- this->video_wrap_offset = this->audio_wrap_offset;
- printf ("to %d\n", this->video_wrap_offset);
+ } else {
- this->wrap_diff_counter = 0;
+ /*
+ * audio and video wrap are not allowed to differ
+ * for too long
+ */
+
+ if ( this->video_wrap_offset != this->audio_wrap_offset
+ && !this->video_discontinuity && !this->audio_discontinuity ) {
+ this->wrap_diff_counter++;
+
+ if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
+
+ printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)",
+ this->video_wrap_offset, this->audio_wrap_offset);
+
+ if (this->video_wrap_offset > this->audio_wrap_offset)
+ this->audio_wrap_offset = this->video_wrap_offset;
+ else
+ this->video_wrap_offset = this->audio_wrap_offset;
+
+ printf ("to %d\n", this->video_wrap_offset);
+
+ this->wrap_diff_counter = 0;
+ }
}
- }
-
- vpts = pts + this->audio_wrap_offset;
-
- /*
- * calc delta to compensate wrong samplerates
- */
-
- if (this->last_audio_pts && (pts>this->last_audio_pts)) {
- int32_t vpts_diff;
-
- vpts_diff = vpts - this->audio_vpts;
+
+ vpts = pts + this->audio_wrap_offset;
- this->audio_pts_delta += vpts_diff*AUDIO_SAMPLE_NUM / (this->num_audio_samples_guessed);
+ /*
+ * calc delta to compensate wrong samplerates
+ */
+
+ if (this->last_audio_pts && (pts>this->last_audio_pts)) {
+ int32_t vpts_diff;
+
+ vpts_diff = vpts - this->audio_vpts;
- if (abs(this->audio_pts_delta) >= MAX_AUDIO_DELTA)
- this->audio_pts_delta = 0;
- }
+ this->audio_pts_delta += vpts_diff*AUDIO_SAMPLE_NUM / (this->num_audio_samples_guessed);
+
+ if (abs(this->audio_pts_delta) >= MAX_AUDIO_DELTA)
+ this->audio_pts_delta = 0;
+ }
+ }
this->num_audio_samples_guessed = 0;
this->last_audio_pts = pts;
diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c
index 4d4c10b6c..99ddefb4e 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.66 2001/12/01 22:38:32 guenter Exp $
+ * $Id: video_decoder.c,v 1.67 2001/12/24 00:45:03 guenter Exp $
*
*/
@@ -76,27 +76,6 @@ void *video_decoder_loop (void *this_gen) {
printf ("video_decoder: getting buffer...\n");
#endif
- /*
-
- I dont know if this will ever work - highly experimental,
- let xine itself detect when to insert still images
-
- if (!this->video_fifo->first) {
-
-#ifdef VIDEO_DECODER_LOG
- printf ("video_decoder: ... inserting still ...\n");
-#endif
-
- buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
-
- buf->type = BUF_VIDEO_FILL ;
- buf->PTS = 0;
- buf->SCR = 0;
- this->cur_input_pos = 0;
- this->cur_input_time = 0;
-
- } else */
-
buf = this->video_fifo->get (this->video_fifo);
if (buf->input_pos)
@@ -202,7 +181,20 @@ void *video_decoder_loop (void *this_gen) {
if (this->cur_video_decoder_plugin)
this->cur_video_decoder_plugin->flush (this->cur_video_decoder_plugin);
+ this->video_in_discontinuity = 1;
+
this->metronom->expect_video_discontinuity (this->metronom);
+
+ this->video_in_discontinuity = 0;
+ this->video_out->still_counter = 0;
+ break;
+
+ case BUF_VIDEO_FILL:
+ break;
+
+ case BUF_CONTROL_FLUSH:
+ if (this->cur_video_decoder_plugin)
+ this->cur_video_decoder_plugin->flush (this->cur_video_decoder_plugin);
break;
case BUF_CONTROL_AUDIO_CHANNEL:
@@ -277,6 +269,8 @@ void video_decoder_init (xine_t *this) {
strerror(err));
exit (1);
}
+
+ this->video_in_discontinuity = 0;
}
void video_decoder_shutdown (xine_t *this) {
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index b4acb22ad..49c2ce12e 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.58 2001/11/28 22:19:12 miguelfreitas Exp $
+ * $Id: video_out.c,v 1.59 2001/12/24 00:45:03 guenter Exp $
*
*/
@@ -33,6 +33,7 @@
#include <string.h>
#include "video_out.h"
+#include "xine_internal.h"
#include "xineutils.h"
/*
@@ -50,7 +51,6 @@ struct img_buf_fifo_s {
pthread_cond_t not_empty;
} ;
-
static img_buf_fifo_t *vo_new_img_buf_queue () {
img_buf_fifo_t *queue;
@@ -95,7 +95,6 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) {
pthread_mutex_lock (&queue->mutex);
while (!queue->first) {
- /* printf ("video_out: queue %d empty...\n", queue); */
pthread_cond_wait (&queue->not_empty, &queue->mutex);
}
@@ -138,19 +137,37 @@ void video_timer_handler (int hubba) {
#endif
}
+/* send a buf to force video_decoder->flush */
+static void video_out_send_decoder_flush( fifo_buffer_t *video_fifo ) {
+ buf_element_t *buf;
+
+ if( !video_fifo )
+ return;
+
+ buf = video_fifo->buffer_pool_alloc (video_fifo);
+
+ buf->type = BUF_CONTROL_FLUSH ;
+ buf->PTS = 0;
+ buf->SCR = 0;
+ buf->input_pos = 0;
+ buf->input_time = 0;
+
+ video_fifo->put (video_fifo, buf);
+
+}
+
+
+
static void *video_out_loop (void *this_gen) {
uint32_t cur_pts;
- int pts_absdiff, diff, absdiff, pts=0;
- vo_frame_t *img;
+ int diff, absdiff, pts=0;
+ vo_frame_t *img, *img_backup;
uint32_t video_step, video_step_new;
vo_instance_t *this = (vo_instance_t *) this_gen;
- sigset_t vo_mask;
static int prof_video_out = -1;
static int prof_spu_blend = -1;
- /*
- int dummysignum;
- */
+ sigset_t vo_mask;
/* printf ("%d video_out start\n", getpid()); */
@@ -159,19 +176,19 @@ static void *video_out_loop (void *this_gen) {
if (prof_spu_blend == -1)
prof_spu_blend = xine_profiler_allocate_slot ("spu blend");
- /*
- sigemptyset(&vo_mask);
- sigaddset(&vo_mask, SIGALRM);
- pthread_sigmask(SIG_UNBLOCK, &vo_mask, NULL);
- */
+ img_backup = NULL;
+ this->still_counter = 0;
+ /*
+ * set up timer signal
+ */
sigemptyset(&vo_mask);
sigaddset(&vo_mask, SIGALRM);
if (sigprocmask (SIG_UNBLOCK, &vo_mask, NULL)) {
printf ("video_out: sigprocmask failed.\n");
}
-#if HAVE_SIGACTION
+#if HAVE_SIGACTION
{
struct sigaction sig_act;
memset (&sig_act, 0, sizeof(sig_act));
@@ -185,49 +202,52 @@ static void *video_out_loop (void *this_gen) {
video_step = this->metronom->get_video_rate (this->metronom);
vo_set_timer (video_step);
+ /*
+ * here it is - the big video output loop
+ */
while ((this->video_loop_running) ||
(!this->video_loop_running && this->display_img_buf_queue->first)) {
+
+ /*
+ * wait until it's time to display a frame
+ */
- /* sigwait(&vo_mask, &dummysignum); */ /* wait for next timer tick */
pause ();
- if( this->video_paused )
- continue;
-
video_step_new = this->metronom->get_video_rate (this->metronom);
if (video_step_new != video_step) {
video_step = video_step_new;
vo_set_timer (video_step);
}
- pts_absdiff = 1000000;
+ /*
+ * now, look at the frame queue and decide which frame to display
+ * or generate still frames if no frames are available
+ */
+
xine_profiler_start_count (prof_video_out);
cur_pts = this->metronom->get_current_time (this->metronom);
-
+
#ifdef VIDEO_OUT_LOG
printf ("video_out : video loop iteration at audio pts %d\n", cur_pts);
#endif
img = this->display_img_buf_queue->first;
-
- if (!img) {
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
/*
* throw away expired frames
*/
-
- do {
+
+ diff = 1000000;
+
+ while (img && (diff >this->pts_per_half_frame)) {
pts = img->PTS;
diff = cur_pts - pts;
absdiff = abs(diff);
if (diff >this->pts_per_half_frame) {
-
printf ( "video_out : throwing away image with pts %d because "
"it's too old (diff : %d > %d).\n",pts,diff,
this->pts_per_half_frame);
@@ -239,8 +259,25 @@ static void *video_out_loop (void *this_gen) {
img->display_locked = 0;
- if (!img->decoder_locked)
- vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
+ /*
+ * last frame? back it up for
+ * still frame creation
+ */
+
+ if (img && !img->next) {
+
+ if (img_backup) {
+#ifdef VIDEO_OUT_LOG
+ printf("video_out : overwriting frame backup\n");
+#endif
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup);
+ }
+
+ img_backup = img;
+ } else {
+ if (!img->decoder_locked)
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
+ }
pthread_mutex_unlock (&img->mutex);
@@ -249,44 +286,141 @@ static void *video_out_loop (void *this_gen) {
if (!img)
diff = -1;
}
- } while (diff >this->pts_per_half_frame);
+ }
- /*
- * time to display frame 0 ?
+ /*
+ * still frame detection:
*/
+ /* no frame? => still frame detection */
+
+ if (!img) {
+
#ifdef VIDEO_OUT_LOG
- printf ("video_out: diff %d\n", diff);
+ printf ("video_out : no frame\n");
#endif
- if (diff<0) {
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
+ if (!this->xine->video_fifo->first || this->xine->video_in_discontinuity) {
+ this->still_counter++;
- /*
- * remove frame from display queue and show it
- */
-
+ if (this->still_counter%8 == 0) {
#ifdef VIDEO_OUT_LOG
- printf ("video_out : displaying image with pts = %d (diff=%d)\n", pts, diff);
+ printf("video_out : sending decoder flush due to inactivity\n");
#endif
-
- img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+ video_out_send_decoder_flush( this->xine->video_fifo );
+ }
+ if (this->still_counter<8) {
+#ifdef VIDEO_OUT_LOG
+ printf("video_out : no frame - waiting %d/8 frames\n", this->still_counter);
+#endif
+ continue;
+ }
- if (!img) {
- xine_profiler_stop_count (prof_video_out);
- continue;
+ if (img_backup) {
+
+#ifdef VIDEO_OUT_LOG
+ printf("video_out : generating still frame \n");
+#endif
+
+ /* keep playing still frames */
+ img = this->duplicate_frame( this, img_backup );
+ img->display_locked = 1;
+ do {
+ img->PTS = this->metronom->got_video_frame(this->metronom, 0, 0);
+ pts = img->PTS;
+ diff = cur_pts - pts;
+
+ } while (diff >this->pts_per_half_frame) ;
+
+ /*
+ * wait until it's time to display this still frame
+ */
+
+ while (pts > cur_pts) {
+ xine_usec_sleep ( 10000 );
+ cur_pts = this->metronom->get_current_time (this->metronom);
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: waiting until it's time to display this still frame\n");
+#endif
+ }
+
+
+ } else {
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out : no frame, but no backup frame\n");
+#endif
+ continue;
+ }
+
+
+ } else {
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out : no frame, but video_fifo size is %d and not in discontinuity\n",
+ this->xine->video_fifo->size(this->xine->video_fifo));
+#endif
+ continue;
+ }
+
+ } else {
+
+ this->still_counter = 0;
+
+ /*
+ * time to display frame >img< ?
+ */
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out : diff %d\n", diff);
+#endif
+
+ if (diff<0) {
+ xine_profiler_stop_count (prof_video_out);
+ continue;
+ }
+
+ /*
+ * last frame? make backup for possible still image
+ */
+ if (img && !img->next) {
+
+ if (img_backup) {
+ printf("video_out : overwriting frame backup\n");
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup);
+ }
+
+ img_backup = this->duplicate_frame(this, img);
+ }
+
+ /*
+ * remove frame from display queue and show it
+ */
+
+ img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+
+ if (!img) {
+ xine_profiler_stop_count (prof_video_out);
+ continue;
+ }
}
+ /*
+ * from this point on, img must be a valid frame for
+ * overlay and output
+ */
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out : displaying image with pts = %d (diff=%d)\n", pts, diff);
+#endif
+
pthread_mutex_lock (&img->mutex);
img->driver_locked = 1;
#ifdef VIDEO_OUT_LOG
if (!img->display_locked)
- printf ("video_out: ALERT! frame was not locked for display queue\n");
+ printf ("video_out : ALERT! frame was not locked for display queue\n");
#endif
img->display_locked = 0;
@@ -331,6 +465,10 @@ static void *video_out_loop (void *this_gen) {
img = this->display_img_buf_queue->first;
}
+ if( img_backup ) {
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup);
+ }
+
pthread_exit(NULL);
}
@@ -345,6 +483,7 @@ static void vo_open (vo_instance_t *this) {
if (!this->video_loop_running) {
this->video_loop_running = 1;
+ this->decoder_started_flag = 0;
pthread_attr_init(&pth_attrs);
pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM);
@@ -352,15 +491,15 @@ static void vo_open (vo_instance_t *this) {
if((err = pthread_create (&this->video_thread,
&pth_attrs, video_out_loop, this)) != 0) {
- printf ("video_out: can't create thread (%s)\n", strerror(err));
+ printf ("video_out : can't create thread (%s)\n", strerror(err));
/* FIXME: how does this happen ? */
- printf ("video_out: sorry, this should not happen. please restart xine.\n");
+ printf ("video_out : sorry, this should not happen. please restart xine.\n");
exit(1);
}
else
- printf ("video_out: thread created\n");
+ printf ("video_out : thread created\n");
} else
- printf ("video_out: vo_open : warning! video thread already running\n");
+ printf ("video_out : vo_open : warning! video thread already running\n");
}
@@ -372,7 +511,7 @@ static vo_frame_t *vo_get_frame (vo_instance_t *this,
vo_frame_t *img;
/*
- printf ("video_out: get_frame %d x %d from queue %d\n",
+ printf ("video_out : get_frame %d x %d from queue %d\n",
width, height, this->free_img_buf_queue);
fflush(stdout);
*/
@@ -404,6 +543,57 @@ static vo_frame_t *vo_get_frame (vo_instance_t *this,
return img;
}
+static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) {
+ vo_frame_t *dupl;
+ int image_size;
+
+ pthread_mutex_unlock (&img->mutex);
+
+ dupl = vo_get_frame( this, img->width, img->height, img->ratio,
+ img->format, img->duration, VO_BOTH_FIELDS );
+
+ pthread_mutex_lock (&dupl->mutex);
+
+ dupl->display_locked = 0;
+ dupl->decoder_locked = 0;
+ dupl->driver_locked = 0;
+
+ image_size = img->width * img->height;
+
+ if (img->format == IMGFMT_YV12) {
+ xine_fast_memcpy(dupl->base[0], img->base[0], image_size);
+ xine_fast_memcpy(dupl->base[1], img->base[1], image_size >> 2);
+ xine_fast_memcpy(dupl->base[2], img->base[2], image_size >> 2);
+ } else {
+ xine_fast_memcpy(dupl->base[0], img->base[0], image_size * 2);
+ }
+
+ dupl->bad_frame = 0;
+ dupl->PTS = dupl->SCR = 0;
+
+ if (img->copy) {
+ int height = img->height;
+ int stride = img->width;
+ uint8_t* src[3];
+
+ src[0] = dupl->base[0];
+ src[1] = dupl->base[1];
+ src[2] = dupl->base[2];
+ while ((height -= 16) >= 0) {
+ dupl->copy(dupl, src);
+ src[0] += 16 * stride;
+ src[1] += 4 * stride;
+ src[2] += 4 * stride;
+ }
+ }
+
+ pthread_mutex_unlock (&dupl->mutex);
+
+ pthread_mutex_unlock (&img->mutex);
+
+ return dupl;
+}
+
static void vo_close (vo_instance_t *this) {
/* this will make sure all hide events were processed */
@@ -481,7 +671,7 @@ static int vo_frame_draw (vo_frame_t *img) {
pic_vpts = this->metronom->got_video_frame (this->metronom, img->PTS, img->SCR);
#ifdef VIDEO_OUT_LOG
- printf ("video_out: got image %d. vpts for picture is %d (pts was %d)\n",
+ printf ("video_out : got image %d. vpts for picture is %d (pts was %d)\n",
img, pic_vpts, img->PTS);
#endif
@@ -489,30 +679,29 @@ static int vo_frame_draw (vo_frame_t *img) {
this->num_frames_delivered++;
cur_vpts = this->metronom->get_current_time(this->metronom);
-
+
diff = pic_vpts - cur_vpts;
frames_to_skip = ((-1 * diff) / this->pts_per_frame + 3) * 2;
-
#ifdef VIDEO_OUT_LOG
- printf ("video_out: delivery diff : %d\n",diff);
+ printf ("video_out : delivery diff : %d\n",diff);
#endif
if (img->display_locked) {
- printf ("video_out: ALERT! frame is already locked for displaying\n");
+ printf ("video_out : ALERT! frame is already locked for displaying\n");
return frames_to_skip;
}
if (cur_vpts>0) {
- if (diff<(-1 * this->pts_per_half_frame)) {
+ if (diff<(-1 * this->pts_per_half_frame) && img->drawn != 2 ) {
this->num_frames_discarded++;
#ifdef VIDEO_OUT_LOG
- printf ("video_out: frame rejected, %d frames to skip\n", frames_to_skip);
+ printf ("video_out : frame rejected, %d frames to skip\n", frames_to_skip);
#endif
- /* printf ("vo_frame_draw: rejected, %d frames to skip\n", frames_to_skip); */
+ printf ("vo_frame_draw: rejected, %d frames to skip\n", frames_to_skip);
pthread_mutex_lock (&img->mutex);
img->display_locked = 0;
@@ -533,7 +722,7 @@ static int vo_frame_draw (vo_frame_t *img) {
*/
#ifdef VIDEO_OUT_LOG
- printf ("video_out: frame is ok => appending to display buffer\n");
+ printf ("video_out : frame is ok => appending to display buffer\n");
#endif
this->last_frame = img;
@@ -575,22 +764,29 @@ static void vo_enable_overlay (vo_instance_t *this, int overlay_enabled) {
this->overlay_enabled = overlay_enabled;
}
-vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
+static void vo_decoder_started (vo_instance_t *this) {
+ this->decoder_started_flag = 1;
+}
+
+vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
vo_instance_t *this;
int i;
this = xine_xmalloc (sizeof (vo_instance_t)) ;
this->driver = driver;
- this->metronom = metronom;
+ this->xine = xine;
+ this->metronom = xine->metronom;
this->open = vo_open;
this->get_frame = vo_get_frame;
+ this->duplicate_frame = vo_duplicate_frame;
this->get_last_frame = vo_get_last_frame;
this->close = vo_close;
this->exit = vo_exit;
this->get_capabilities = vo_get_capabilities;
this->enable_ovl = vo_enable_overlay;
+ this->decoder_started = vo_decoder_started;
this->num_frames_delivered = 0;
this->num_frames_skipped = 0;
diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
index d3dc51afa..69b808970 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.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: video_out.h,v 1.32 2001/12/14 16:50:57 f1rmb Exp $
+ * $Id: video_out.h,v 1.33 2001/12/24 00:45:03 guenter Exp $
*
*
* xine version of video_out.h
@@ -41,9 +41,11 @@ extern "C" {
#if defined(XINE_COMPILE)
#include "configfile.h"
#include "metronom.h"
+#include "buffer.h"
#else
#include "xine/configfile.h"
#include "xine/metronom.h"
+#include "xine/buffer.h"
#endif
#define VIDEO_OUT_PLUGIN_IFACE_VERSION 1
@@ -54,6 +56,7 @@ typedef struct vo_instance_s vo_instance_t;
typedef struct img_buf_fifo_s img_buf_fifo_t;
typedef struct vo_overlay_s vo_overlay_t;
typedef struct video_overlay_instance_s video_overlay_instance_t;
+typedef struct xine_s xine_t;
/* public part, video drivers may add private fields */
@@ -124,10 +127,19 @@ struct vo_instance_s {
vo_frame_t* (*get_last_frame) (vo_instance_t *this);
+ /*
+ * duplicate_frame - allocate an image buffer from display driver
+ * and copy the frame into it.
+ */
+ vo_frame_t* (*duplicate_frame) (vo_instance_t *this, vo_frame_t *img );
+
/* overlay stuff */
void (*enable_ovl) (vo_instance_t *this, int ovl_enable);
video_overlay_instance_t *overlay_source;
int overlay_enabled;
+
+ /* this is just a hint to video_out to detect single frame streams */
+ void (*decoder_started) (vo_instance_t *this);
/* video driver is no longer used by decoder => close */
void (*close) (vo_instance_t *this);
@@ -139,6 +151,7 @@ struct vo_instance_s {
vo_driver_t *driver;
metronom_t *metronom;
+ xine_t *xine;
img_buf_fifo_t *free_img_buf_queue;
img_buf_fifo_t *display_img_buf_queue;
@@ -156,6 +169,8 @@ struct vo_instance_s {
int num_frames_skipped;
int num_frames_discarded;
+ int decoder_started_flag;
+ int still_counter;/* still_counter>8 => still frames will be generated */
} ;
/* constants for the get/set property functions */
@@ -337,7 +352,7 @@ video_overlay_instance_t *video_overlay_new_instance ();
* a given video driver
*/
-vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) ;
+vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) ;
/*
* to build a dynamic video output plugin
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 771abc538..0c7725a0d 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.92 2001/12/14 23:54:56 f1rmb Exp $
+ * $Id: xine.c,v 1.93 2001/12/24 00:45:03 guenter Exp $
*
* top-level xine functions
*
@@ -486,7 +486,7 @@ xine_t *xine_init (vo_driver_t *vo,
load_decoder_plugins (this, config, DECODER_PLUGIN_IFACE_VERSION);
- this->video_out = vo_new_instance (vo, this->metronom);
+ this->video_out = vo_new_instance (vo, this);
video_decoder_init (this);
this->osd_renderer = osd_renderer_init( this->video_out->overlay_source, config );
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index 04021648b..9421ed650 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.65 2001/12/13 22:47:14 miguelfreitas Exp $
+ * $Id: xine_internal.h,v 1.66 2001/12/24 00:45:03 guenter Exp $
*
*/
@@ -141,8 +141,6 @@ struct audio_decoder_s {
#define XINE_LOG_CODEC 1
#define XINE_LOG_NUM 2 /* # of log buffers defined */
-typedef struct xine_s xine_t;
-
typedef void (*xine_event_listener_t) (void *user_data, xine_event_t *);
struct xine_s {
@@ -192,6 +190,7 @@ struct xine_s {
video_decoder_t *video_decoder_plugins[DECODER_PLUGIN_MAX];
video_decoder_t *cur_video_decoder_plugin;
int video_finished;
+ int video_in_discontinuity;
osd_renderer_t *osd_renderer;
osd_object_t *osd;