diff options
-rw-r--r-- | src/xine-engine/metronom.c | 44 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 219 |
2 files changed, 169 insertions, 94 deletions
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index 86755fe6b..65d62966d 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.47 2002/01/02 18:16:08 jkeil Exp $ + * $Id: metronom.c,v 1.48 2002/01/06 00:49:01 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -401,7 +401,18 @@ static void metronom_set_video_rate (metronom_t *this, uint32_t pts_per_frame) { } static uint32_t metronom_get_video_rate (metronom_t *this) { - return this->avg_frame_duration; + int ret; + + pthread_mutex_lock (&this->lock); + ret = this->avg_frame_duration; + pthread_mutex_unlock (&this->lock); + + /* this is due bad streams, but returning 0 will + cause problems to video out timer setting. */ + if( ret < 100 ) + ret = 100; + + return ret; } static void metronom_set_audio_rate (metronom_t *this, uint32_t pts_per_smpls) { @@ -500,6 +511,21 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32 int pts_discontinuity = 0; pthread_mutex_lock (&this->lock); + + if( (this->audio_discontinuity || this->audio_stream_starting) && + (this->video_discontinuity || this->video_stream_starting) ) { + + /* this is needed to take care of still frame with no audio + were vpts are not updated. + we can only do it here because audio and video decoder threads + have just been synced */ + if ( this->video_vpts < metronom_get_current_time(this) ) { + this->video_vpts = metronom_get_current_time(this) + PREBUFFER_PTS_OFFSET; + this->audio_vpts = this->video_vpts; + LOG_MSG(this->xine, _("metronom: audio/video vpts too old, adjusted to %d\n"), + this->video_vpts); + } + } /* check for pts discontinuities against the predicted pts value */ if (pts && this->last_video_pts) { @@ -701,6 +727,20 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, pthread_mutex_lock (&this->lock); + if( (this->audio_discontinuity || this->audio_stream_starting) && + (this->video_discontinuity || this->video_stream_starting) ) { + + /* this is needed to take care of still frame with no audio + were vpts are not updated. + we can only do it here because audio and video decoder threads + have just been synced */ + if ( this->audio_vpts < metronom_get_current_time(this) ) { + this->audio_vpts = metronom_get_current_time(this) + PREBUFFER_PTS_OFFSET; + this->video_vpts = this->audio_vpts; + LOG_MSG(this->xine, _("metronom: audio/video vpts too old, adjusted to %d\n"), + this->audio_vpts); + } + } this->last_audio_scr = scr; diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index c1e808bc9..424b3968d 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.62 2002/01/02 18:16:08 jkeil Exp $ + * $Id: video_out.c,v 1.63 2002/01/06 00:49:01 guenter Exp $ * */ @@ -91,6 +91,11 @@ static void vo_append_to_img_buf_queue (img_buf_fifo_t *queue, pthread_mutex_lock (&queue->mutex); + /* img already enqueue? (serious leak) + if( img->next ) + *(char *)0=0; + */ + img->next = NULL; if (!queue->first) { @@ -188,6 +193,9 @@ static void *video_out_loop (void *this_gen) { static int prof_video_out = -1; static int prof_spu_blend = -1; sigset_t vo_mask; + + uint32_t last_draw_vpts = 0; + int flush_sent = 0; /* printf ("%d video_out start\n", getpid()); */ @@ -197,7 +205,6 @@ static void *video_out_loop (void *this_gen) { prof_spu_blend = xine_profiler_allocate_slot ("spu blend"); img_backup = NULL; - this->still_counter = 0; /* * set up timer signal @@ -226,8 +233,7 @@ static void *video_out_loop (void *this_gen) { * here it is - the big video output loop */ - while ((this->video_loop_running) || - (!this->video_loop_running && this->display_img_buf_queue->first)) { + while ( this->video_loop_running ) { /* * wait until it's time to display a frame @@ -238,6 +244,7 @@ static void *video_out_loop (void *this_gen) { 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); } @@ -256,6 +263,23 @@ static void *video_out_loop (void *this_gen) { img = this->display_img_buf_queue->first; + /* update timer for inactivity flush */ + if( img ) { + last_draw_vpts = cur_pts; + } else { + /* start timer when decoder receives the first packet */ + if( !last_draw_vpts && this->decoder_started_flag ) + last_draw_vpts = cur_pts; + + if( last_draw_vpts && (cur_pts - last_draw_vpts) > (8 * this->pts_per_frame) ) { + printf("video_out : sending decoder flush due to inactivity\n"); + video_out_send_decoder_flush( this->xine->video_fifo ); + last_draw_vpts = cur_pts; + flush_sent = 1; + } + } + + /* * throw away expired frames */ @@ -275,36 +299,42 @@ static void *video_out_loop (void *this_gen) { this->num_frames_discarded++; img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); - pthread_mutex_lock (&img->mutex); - - img->display_locked = 0; /* * last frame? back it up for * still frame creation */ - if (img && !img->next) { + if (!this->display_img_buf_queue->first) { if (img_backup) { + pthread_mutex_lock (&img_backup->mutex); #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->display_locked = 0; + if (!img->decoder_locked) + vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + + pthread_mutex_unlock (&img_backup->mutex); } - + printf("video_out : possible still frame (old)\n"); + flush_sent = 0; + + /* we must not clear display_locked from img_backup. + without it decoder may try to free our backup. */ img_backup = img; } else { + pthread_mutex_lock (&img->mutex); + + img->display_locked = 0; if (!img->decoder_locked) vo_append_to_img_buf_queue (this->free_img_buf_queue, img); + + pthread_mutex_unlock (&img->mutex); } - - pthread_mutex_unlock (&img->mutex); - + img = this->display_img_buf_queue->first; - - if (!img) - diff = -1; } } @@ -320,74 +350,45 @@ static void *video_out_loop (void *this_gen) { printf ("video_out : no frame\n"); #endif - if (!this->xine->video_fifo->first || this->xine->video_in_discontinuity) { + if (img_backup) { - this->still_counter++; - - if (this->still_counter%8 == 0) { -#ifdef VIDEO_OUT_LOG - printf("video_out : sending decoder flush due to inactivity\n"); -#endif - 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_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 - */ + /* + * wait until it's time to display this still frame + */ + pts = this->metronom->get_current_time (this->metronom); + do { + xine_usec_sleep ( 10000 ); + cur_pts = this->metronom->get_current_time (this->metronom); + diff = cur_pts - pts; - 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 - } + } while (diff < 2 * this->pts_per_frame) ; - - } else { -#ifdef VIDEO_OUT_LOG - printf ("video_out : no frame, but no backup frame\n"); -#endif + /* if some frame arrived dont generate still */ + if( this->display_img_buf_queue->first ) { + xine_profiler_stop_count (prof_video_out); continue; } +//#ifdef VIDEO_OUT_LOG + printf("video_out : generating still frame (cur_pts = %d) \n", cur_pts); +//#endif + + /* keep playing still frames */ + img = this->duplicate_frame( this, img_backup ); + img->display_locked = 1; + + img->PTS = cur_pts; + diff = 0; } 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)); + printf ("video_out : no frame, but no backup frame\n"); #endif + xine_profiler_stop_count (prof_video_out); continue; } - } else { - this->still_counter = 0; - /* * time to display frame >img< ? */ @@ -401,25 +402,37 @@ static void *video_out_loop (void *this_gen) { continue; } + if (img_backup) { + pthread_mutex_lock (&img_backup->mutex); + printf("video_out : freeing frame backup\n"); + img_backup->display_locked = 0; + if( !img_backup->decoder_locked ) + vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + pthread_mutex_unlock (&img_backup->mutex); + img_backup = NULL; + } + /* * last frame? make backup for possible still image */ - if (img && !img->next) { + if (img && !img->next && + (this->xine->video_fifo->size(this->xine->video_fifo) < 10 || + flush_sent || this->xine->video_in_discontinuity) ) { - if (img_backup) { - LOG_MSG(this->xine, _("video_out : overwriting frame backup\n")); - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); - } + printf("video_out : possible still frame (fifosize = %d, flushsent=%d)\n", + this->xine->video_fifo->size(this->xine->video_fifo), flush_sent); img_backup = this->duplicate_frame(this, img); } + flush_sent = 0; + /* * 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; @@ -476,17 +489,23 @@ static void *video_out_loop (void *this_gen) { img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); pthread_mutex_lock (&img->mutex); + img->display_locked = 0; if (!img->decoder_locked) vo_append_to_img_buf_queue (this->free_img_buf_queue, img); - img->display_locked = 0; pthread_mutex_unlock (&img->mutex); img = this->display_img_buf_queue->first; } if( img_backup ) { - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + pthread_mutex_lock (&img_backup->mutex); + + img_backup->display_locked = 0; + if( !img_backup->decoder_locked ) + vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + + pthread_mutex_unlock (&img_backup->mutex); } pthread_exit(NULL); @@ -553,7 +572,8 @@ static vo_frame_t *vo_get_frame (vo_instance_t *this, img->ratio = ratio; img->format = format; img->duration = duration; - + img->drawn = 0; + /* let driver ensure this image has the right format */ this->driver->update_frame_format (this->driver, img, width, height, ratio, format, flags); @@ -599,19 +619,34 @@ static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) { /* Support copy; Dangerous, since some decoders may use a source that's * not dupl->base. It's up to the copy implementation to check for NULL */ - if (img->copy) { - int height = img->height; - int stride = img->width; - uint8_t* src[3]; + if (img->format == IMGFMT_YV12) { + 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; + 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; + } + } + } else { + if (img->copy) { + int height = img->height; + int stride = img->width; + uint8_t* src[3]; + + src[0] = dupl->base[0]; + + while ((height -= 16) >= 0) { + dupl->copy(dupl, src); + src[0] += 32 * stride; + } } } @@ -729,7 +764,7 @@ static int vo_frame_draw (vo_frame_t *img) { printf ("video_out : frame rejected, %d frames to skip\n", frames_to_skip); #endif - LOG_MSG(this->xine, _("vo_frame_draw: rejected, %d frames to skip\n"), frames_to_skip); + LOG_MSG(this->xine, _("video_out: rejected, %d frames to skip\n"), frames_to_skip); pthread_mutex_lock (&img->mutex); img->display_locked = 0; |