diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2002-07-30 00:26:45 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2002-07-30 00:26:45 +0000 |
commit | 0daeb9d1c6f90b0b364421c2ef9e95b3cd6d3aa1 (patch) | |
tree | fdd8b147ae712c52e6c40251a9f87ee98a831d4b | |
parent | d18ad5e4e7bcbef62d7e8facd1ee401dc5d7e39c (diff) | |
download | xine-lib-0daeb9d1c6f90b0b364421c2ef9e95b3cd6d3aa1.tar.gz xine-lib-0daeb9d1c6f90b0b364421c2ef9e95b3cd6d3aa1.tar.bz2 |
- video out fixes (never trigged deadlocks and erroneous flush of overlay
events)
- duplicate_frame is now internal use only (api function deprecated)
- special case for redrawing screen in paused mode (due overlay changes,
resize, window movement, brightness adjusting etc)
- xshm brightness may be adjusted with video paused
CVS patchset: 2363
CVS date: 2002/07/30 00:26:45
-rw-r--r-- | src/video_out/video_out_xshm.c | 24 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 250 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 7 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 7 |
4 files changed, 187 insertions, 101 deletions
diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c index 2a2e98317..55f78da14 100644 --- a/src/video_out/video_out_xshm.c +++ b/src/video_out/video_out_xshm.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_xshm.c,v 1.81 2002/07/20 21:46:05 esnel Exp $ + * $Id: video_out_xshm.c,v 1.82 2002/07/30 00:26:45 miguelfreitas Exp $ * * video_out_xshm.c, X11 shared memory extension interface for xine * @@ -74,7 +74,7 @@ typedef struct xshm_frame_s { int format; int flags; - int user_ratio; + int user_ratio; /* * "ideal" size of this frame : @@ -136,6 +136,9 @@ typedef struct xshm_driver_s { uint8_t *yuv2rgb_cmap; yuv2rgb_factory_t *yuv2rgb_factory; int user_ratio; + + /* force update screen if gamma changes */ + int force_redraw; /* speed tradeoffs */ int scaling_disabled; @@ -809,8 +812,8 @@ static int xshm_redraw_needed (vo_driver_t *this_gen) { int gui_x, gui_y, gui_width, gui_height, gui_win_x, gui_win_y; int ret = 0; - if( this->cur_frame ) - { + if( this->cur_frame ) { + this->frame_output_cb (this->user_data, this->cur_frame->ideal_width, this->cur_frame->ideal_height, &gui_x, &gui_y, &gui_width, &gui_height, @@ -834,10 +837,11 @@ static int xshm_redraw_needed (vo_driver_t *this_gen) { } } else - { ret = 1; - } - + + if( this->force_redraw ) + ret = 1; + return ret; } @@ -904,7 +908,8 @@ static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { } this->cur_frame = frame; - + this->force_redraw = 0; + xoffset = (this->gui_width - frame->output_width) / 2 + this->gui_x; yoffset = (this->gui_height - frame->output_height) / 2 + this->gui_y; @@ -1005,7 +1010,10 @@ static int xshm_set_property (vo_driver_t *this_gen, this->yuv2rgb_gamma = value; this->yuv2rgb_factory->set_gamma (this->yuv2rgb_factory, value); + this->force_redraw = 1; +#ifdef LOG printf ("video_out_xshm: gamma changed to %d\n",value); +#endif } else { printf ("video_out_xshm: tried to set unsupported property %d\n", property); } diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index f1f4261f7..c54a82932 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.100 2002/07/15 21:42:34 esnel Exp $ + * $Id: video_out.c,v 1.101 2002/07/30 00:26:45 miguelfreitas Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -87,6 +87,7 @@ struct img_buf_fifo_s { vo_frame_t *last; int num_buffers; + int locked_for_read; pthread_mutex_t mutex; pthread_cond_t not_empty; } ; @@ -100,6 +101,7 @@ static img_buf_fifo_t *vo_new_img_buf_queue () { queue->first = NULL; queue->last = NULL; queue->num_buffers = 0; + queue->locked_for_read = 0; pthread_mutex_init (&queue->mutex, NULL); pthread_cond_init (&queue->not_empty, NULL); } @@ -137,7 +139,7 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { pthread_mutex_lock (&queue->mutex); - while (!queue->first) { + while (!queue->first || queue->locked_for_read) { pthread_cond_wait (&queue->not_empty, &queue->mutex); } @@ -149,10 +151,6 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { if (!queue->first) { queue->last = NULL; queue->num_buffers = 0; - /* I think this is a (pretty long-standing) bug - guenter 21/03/2002 - pthread_cond_init (&queue->not_empty, NULL); - */ } else { queue->num_buffers--; @@ -323,6 +321,99 @@ static int vo_frame_draw (vo_frame_t *img) { * */ +/* duplicate_frame(): this function is used to keep playing frames + * while video is still or player paused. + * + * frame allocation inside vo loop is dangerous: + * we must never wait for a free frame -> deadlock condition. + * to avoid deadlocks we don't use vo_remove_from_img_buf_queue() + * and reimplement a slightly modified version here. + * free_img_buf_queue->mutex must be grabbed prior entering it. + * (must assure that free frames won't be exhausted by decoder thread). + */ +static vo_frame_t * duplicate_frame( vos_t *this, vo_frame_t *img ) { + + vo_frame_t *dupl; + int image_size; + + if( !this->free_img_buf_queue->first) + return NULL; + + dupl = this->free_img_buf_queue->first; + this->free_img_buf_queue->first = dupl->next; + dupl->next = NULL; + if (!this->free_img_buf_queue->first) { + this->free_img_buf_queue->last = NULL; + this->free_img_buf_queue->num_buffers = 0; + } + else { + this->free_img_buf_queue->num_buffers--; + } + + pthread_mutex_lock (&dupl->mutex); + dupl->lock_counter = 1; + dupl->width = img->width; + dupl->height = img->height; + dupl->ratio = img->ratio; + dupl->format = img->format; + + this->driver->update_frame_format (this->driver, dupl, dupl->width, dupl->height, + dupl->ratio, dupl->format, VO_BOTH_FIELDS); + + pthread_mutex_unlock (&dupl->mutex); + + image_size = img->pitches[0] * img->height; + + if (img->format == IMGFMT_YV12) { + if (img->base[0]) + xine_fast_memcpy(dupl->base[0], img->base[0], image_size); + if (img->base[1]) + xine_fast_memcpy(dupl->base[1], img->base[1], img->pitches[1] * ((img->height+1)/2)); + if (img->base[2]) + xine_fast_memcpy(dupl->base[2], img->base[2], img->pitches[2] * ((img->height+1)/2)); + } else { + if (img->base[0]) + xine_fast_memcpy(dupl->base[0], img->base[0], image_size); + } + + dupl->bad_frame = 0; + dupl->pts = 0; + dupl->vpts = 0; + dupl->duration = img->duration; + + if (img->format == IMGFMT_YV12) { + if (img->copy) { + int height = img->height; + 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 * img->pitches[0]; + src[1] += 8 * img->pitches[1]; + src[2] += 8 * img->pitches[2]; + } + } + } else { + if (img->copy) { + int height = img->height; + uint8_t* src[3]; + + src[0] = dupl->base[0]; + + while ((height -= 16) >= 0) { + dupl->copy(dupl, src); + src[0] += 16 * img->pitches[0]; + } + } + } + + return dupl; +} + + static void expire_frames (vos_t *this, int64_t cur_vpts) { int64_t pts; @@ -409,11 +500,14 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) { printf("video_out: generating still frame (cur_vpts = %lld) \n", cur_vpts); #endif - + /* keep playing still frames */ - img = this->vo.duplicate_frame (&this->vo, this->img_backup ); - img->vpts = cur_vpts; - + pthread_mutex_lock( &this->free_img_buf_queue->mutex ); + img = duplicate_frame (this, this->img_backup ); + pthread_mutex_unlock( &this->free_img_buf_queue->mutex ); + if( img ) + img->vpts = cur_vpts; + return img; } else { @@ -453,6 +547,7 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) { /* * last frame? make backup for possible still image */ + pthread_mutex_lock( &this->free_img_buf_queue->mutex ); if (img && !img->next && (this->xine->video_fifo->size(this->xine->video_fifo) < 10 || this->xine->video_in_discontinuity) ) { @@ -460,8 +555,9 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) { printf ("video_out: possible still frame (fifosize = %d)\n", this->xine->video_fifo->size(this->xine->video_fifo)); - this->img_backup = this->vo.duplicate_frame (&this->vo, img); + this->img_backup = duplicate_frame (this, img); } + pthread_mutex_unlock( &this->free_img_buf_queue->mutex ); /* * remove frame from display queue and show it @@ -474,7 +570,7 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) { } static void overlay_and_display_frame (vos_t *this, - vo_frame_t *img) { + vo_frame_t *img, int64_t vpts) { #ifdef LOG printf ("video_out: displaying image with vpts = %lld\n", @@ -482,11 +578,8 @@ static void overlay_and_display_frame (vos_t *this, #endif if (this->overlay_source) { - /* This is the only way for the overlay manager to get pts values - * for flushing its buffers. So don't remove it! */ - this->overlay_source->multiple_overlay_blend (this->overlay_source, - img->vpts, + vpts, this->driver, img, this->video_loop_running && this->overlay_enabled); } @@ -506,9 +599,6 @@ static void overlay_and_display_frame (vos_t *this, static void check_redraw_needed (vos_t *this, int64_t vpts) { if (this->overlay_source) { - /* This is the only way for the overlay manager to get pts values - * for flushing its buffers. So don't remove it! */ - if( this->overlay_source->redraw_needed (this->overlay_source, vpts) ) this->redraw_needed = 1; } @@ -517,6 +607,57 @@ static void check_redraw_needed (vos_t *this, int64_t vpts) { this->redraw_needed = 1; } +/* special loop for paused mode + * needed to update screen due overlay changes, resize, window + * movement, brightness adjusting etc. + */ +static void paused_loop( vos_t *this, int64_t vpts ) +{ + vo_frame_t *img; + + pthread_mutex_lock( &this->free_img_buf_queue->mutex ); + /* prevent decoder thread from allocating new frames */ + this->free_img_buf_queue->locked_for_read = 1; + + while( this->xine->speed == SPEED_PAUSE ) { + + /* we need at least one free frame to keep going */ + if( this->display_img_buf_queue->first && + !this->free_img_buf_queue->first ) { + + img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); + img->next = NULL; + this->free_img_buf_queue->first = img; + this->free_img_buf_queue->last = img; + this->free_img_buf_queue->num_buffers = 1; + } + + /* set img_backup to play the same frame several times */ + if( this->display_img_buf_queue->first && !this->img_backup ) { + this->img_backup = vo_remove_from_img_buf_queue (this->display_img_buf_queue); + this->redraw_needed = 1; + } + + check_redraw_needed( this, vpts ); + + if( this->redraw_needed && this->img_backup ) { + img = duplicate_frame (this, this->img_backup ); + if( img ) { + pthread_mutex_unlock( &this->free_img_buf_queue->mutex ); + overlay_and_display_frame (this, img, vpts); + pthread_mutex_lock( &this->free_img_buf_queue->mutex ); + } + } + + xine_usec_sleep (20000); + } + + this->free_img_buf_queue->locked_for_read = 0; + + if( this->free_img_buf_queue->first ) + pthread_cond_signal (&this->free_img_buf_queue->not_empty); + pthread_mutex_unlock( &this->free_img_buf_queue->mutex ); +} static void *video_out_loop (void *this_gen) { @@ -559,7 +700,7 @@ static void *video_out_loop (void *this_gen) { #ifdef LOG printf ("video_out: displaying frame (id=%d)\n", img->id); #endif - overlay_and_display_frame (this, img); + overlay_and_display_frame (this, img, vpts); } else { @@ -604,6 +745,9 @@ static void *video_out_loop (void *this_gen) { do { vpts = this->metronom->get_current_time (this->metronom); + + if( this->xine->speed == SPEED_PAUSE ) + paused_loop( this, vpts ); usec_to_sleep = (next_frame_vpts - vpts) * 100 / 9; @@ -653,70 +797,6 @@ static uint32_t vo_get_capabilities (vo_instance_t *this_gen) { return this->driver->get_capabilities (this->driver); } -static vo_frame_t * vo_duplicate_frame( vo_instance_t *this_gen, vo_frame_t *img ) { - - vo_frame_t *dupl; - /* vos_t *this = (vos_t *) this_gen; */ - int image_size; - - dupl = vo_get_frame (this_gen, img->width, img->height, img->ratio, - img->format, VO_BOTH_FIELDS ); - - image_size = img->pitches[0] * img->height; - - if (img->format == IMGFMT_YV12) { - /* The dxr3 video out plugin does not allocate memory for the dxr3 - * decoder, so we must check for NULL */ - if (img->base[0]) - xine_fast_memcpy(dupl->base[0], img->base[0], image_size); - if (img->base[1]) - xine_fast_memcpy(dupl->base[1], img->base[1], img->pitches[1] * ((img->height+1)/2)); - if (img->base[2]) - xine_fast_memcpy(dupl->base[2], img->base[2], img->pitches[2] * ((img->height+1)/2)); - } else { - if (img->base[0]) - xine_fast_memcpy(dupl->base[0], img->base[0], image_size); - } - - dupl->bad_frame = 0; - dupl->pts = 0; - dupl->vpts = 0; - dupl->duration = img->duration; - - /* 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->format == IMGFMT_YV12) { - if (img->copy) { - int height = img->height; - 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 * img->pitches[0]; - src[1] += 8 * img->pitches[1]; - src[2] += 8 * img->pitches[2]; - } - } - } else { - if (img->copy) { - int height = img->height; - uint8_t* src[3]; - - src[0] = dupl->base[0]; - - while ((height -= 16) >= 0) { - dupl->copy(dupl, src); - src[0] += 16 * img->pitches[0]; - } - } - } - - return dupl; -} - static void vo_open (vo_instance_t *this_gen) { vos_t *this = (vos_t *) this_gen; @@ -822,7 +902,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { this->vo.open = vo_open; this->vo.get_frame = vo_get_frame; - this->vo.duplicate_frame = vo_duplicate_frame; + this->vo.duplicate_frame = NULL; /* deprecated */ this->vo.get_last_frame = vo_get_last_frame; this->vo.close = vo_close; this->vo.exit = vo_exit; diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 13a8df7f5..9f52e29a3 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.55 2002/07/15 21:42:34 esnel Exp $ + * $Id: video_out.h,v 1.56 2002/07/30 00:26:45 miguelfreitas Exp $ * * * xine version of video_out.h @@ -154,8 +154,9 @@ 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. + * duplicate_frame is deprecated and should be removed + * on the next api change. + * (will remain as an internal function only) */ vo_frame_t* (*duplicate_frame) (vo_instance_t *this, vo_frame_t *img ); diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 80c9642e3..e4a43505e 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.145 2002/07/14 20:55:17 miguelfreitas Exp $ + * $Id: xine.c,v 1.146 2002/07/30 00:26:45 miguelfreitas Exp $ * * top-level xine functions * @@ -859,7 +859,7 @@ void xine_set_speed (xine_t *this, int speed) { pthread_mutex_lock (&this->osd_lock); switch (speed) { case SPEED_PAUSE: - xine_internal_osd (this, "<", 10000); + xine_internal_osd (this, "<", 90000); break; case SPEED_SLOW_4: xine_internal_osd (this, "<>", 20000 * speed); @@ -879,9 +879,6 @@ void xine_set_speed (xine_t *this, int speed) { } pthread_mutex_unlock (&this->osd_lock); - /* make sure osd can be displayed */ - xine_usec_sleep(100000); - printf ("xine: set_speed %d\n", speed); xine_set_speed_internal (this, speed); |