summaryrefslogtreecommitdiff
path: root/src/xine-engine/video_out.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/video_out.c')
-rw-r--r--src/xine-engine/video_out.c985
1 files changed, 497 insertions, 488 deletions
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index 8f43d71ce..10a327045 100644
--- a/src/xine-engine/video_out.c
+++ b/src/xine-engine/video_out.c
@@ -17,8 +17,9 @@
* 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.70 2002/02/02 13:39:30 miguelfreitas Exp $
+ * $Id: video_out.c,v 1.71 2002/02/09 07:13:24 guenter Exp $
*
+ * frame allocation / queuing / scheduling / output functions
*/
#ifdef HAVE_CONFIG_H
@@ -34,6 +35,7 @@
#include <zlib.h>
#include "video_out.h"
+#include "metronom.h"
#include "xine_internal.h"
#include "xineutils.h"
@@ -57,12 +59,48 @@
}
#endif
-/*
+
#define VIDEO_OUT_LOG
-*/
#define NUM_FRAME_BUFFERS 15
+typedef struct {
+
+ vo_instance_t vo; /* public part */
+
+ 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;
+
+ vo_frame_t *last_frame;
+ vo_frame_t *img_backup;
+ int backup_is_logo;
+
+ int video_loop_running;
+ int video_opened;
+ pthread_t video_thread;
+
+ int num_frames_delivered;
+ int num_frames_skipped;
+ int num_frames_discarded;
+
+ /* pts value when decoder delivered last video frame */
+ int64_t last_delivery_pts;
+
+ int logo_w, logo_h;
+ uint8_t *logo_yuy2;
+
+ video_overlay_instance_t *overlay_source;
+ int overlay_enabled;
+} vos_t;
+
+/*
+ * frame queue (fifo) util functions
+ */
+
struct img_buf_fifo_s {
vo_frame_t *first;
vo_frame_t *last;
@@ -144,439 +182,521 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) {
return img;
}
-static void vo_set_timer (uint32_t video_step) {
- struct itimerval tval;
-
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = video_step*100000/90000;
- tval.it_value.tv_sec = 0;
- tval.it_value.tv_usec = video_step*100000/90000;
-
- if (setitimer(ITIMER_REAL, &tval, NULL)) {
- printf ("vo_set_timer: setitimer failed :");
- }
-}
+/*
+ * function called by video output driver
+ */
-void video_timer_handler (int hubba) {
-#if !HAVE_SIGACTION
- signal (SIGALRM, video_timer_handler);
-#endif
-}
+static void vo_frame_displayed (vo_frame_t *img) {
-/* send a buf to force video_decoder->flush */
-static void video_out_send_decoder_flush( fifo_buffer_t *video_fifo ) {
- buf_element_t *buf;
+ pthread_mutex_lock (&img->mutex);
- 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;
+ img->driver_locked = 0;
- video_fifo->put (video_fifo, buf);
+ if (!img->decoder_locked) {
+ vos_t *this = (vos_t *) img->instance;
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
+ }
+ pthread_mutex_unlock (&img->mutex);
}
-static vo_frame_t *vo_get_frame (vo_instance_t *this,
+/*
+ *
+ * functions called by video decoder:
+ *
+ * get_frame => alloc frame for rendering
+ *
+ * frame_draw=> queue finished frame for display
+ *
+ * frame_free=> frame no longer used as reference frame by decoder
+ *
+ */
+
+static vo_frame_t *vo_get_frame (vo_instance_t *this_gen,
uint32_t width, uint32_t height,
- int ratio, int format, uint32_t duration,
+ int ratio, int format,
int flags) {
vo_frame_t *img;
+ vos_t *this = (vos_t *) this_gen;
- /*
- printf ("video_out : get_frame %d x %d from queue %d\n",
- width, height, this->free_img_buf_queue);
- fflush(stdout);
- */
-
- if (this->pts_per_frame != duration) {
- this->pts_per_frame = duration;
- this->pts_per_half_frame = duration / 2;
- this->metronom->set_video_rate (this->metronom, duration);
- }
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: get_frame (%d x %d)\n", width, height);
+#endif
img = vo_remove_from_img_buf_queue (this->free_img_buf_queue);
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: got a frame -> pthread_mutex_lock (&img->mutex)\n");
+#endif
+
pthread_mutex_lock (&img->mutex);
img->display_locked = 0;
img->decoder_locked = 1;
img->driver_locked = 0;
- img->width = width;
- img->height = height;
- img->ratio = ratio;
- img->format = format;
- img->duration = duration;
- img->drawn = 0;
+ img->width = width;
+ img->height = height;
+ img->ratio = ratio;
+ img->format = format;
/* let driver ensure this image has the right format */
- this->driver->update_frame_format (this->driver, img, width, height, ratio, format, flags);
+ this->driver->update_frame_format (this->driver, img, width, height,
+ ratio, format, flags);
pthread_mutex_unlock (&img->mutex);
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: get_frame (%d x %d) done\n", width, height);
+#endif
+
return img;
}
-static void *video_out_loop (void *this_gen) {
+static int vo_frame_draw (vo_frame_t *img) {
- uint32_t cur_pts;
- int diff, absdiff, pts=0;
- vo_frame_t *img, *img_backup;
- int backup_is_logo = 0;
- uint32_t video_step, video_step_new;
- vo_instance_t *this = (vo_instance_t *) this_gen;
- static int prof_video_out = -1;
- static int prof_spu_blend = -1;
- sigset_t vo_mask;
-
- int flush_sent = 0;
+ vos_t *this = (vos_t *) img->instance;
+ int64_t diff;
+ int64_t cur_vpts;
+ int64_t pic_vpts ;
+ int frames_to_skip;
- /* printf ("%d video_out start\n", getpid()); */
+ this->metronom->got_video_frame (this->metronom, img);
- if (prof_video_out == -1)
- prof_video_out = xine_profiler_allocate_slot ("video output");
- if (prof_spu_blend == -1)
- prof_spu_blend = xine_profiler_allocate_slot ("spu blend");
+ pic_vpts = img->vpts;
- img_backup = NULL;
- this->last_draw_vpts = 0;
-
- /*
- * set up timer signal
- */
-
- sigemptyset(&vo_mask);
- sigaddset(&vo_mask, SIGALRM);
- if (sigprocmask (SIG_UNBLOCK, &vo_mask, NULL)) {
- LOG_MSG(this->xine, _("video_out: sigprocmask failed.\n"));
- }
-#if HAVE_SIGACTION
- {
- struct sigaction sig_act;
- memset (&sig_act, 0, sizeof(sig_act));
- sig_act.sa_handler = video_timer_handler;
- sigaction (SIGALRM, &sig_act, NULL);
- }
-#else
- signal (SIGALRM, video_timer_handler);
-#endif
+ cur_vpts = this->metronom->get_current_time(this->metronom);
+ this->last_delivery_pts = cur_vpts;
- video_step = this->metronom->get_video_rate (this->metronom);
- vo_set_timer (video_step);
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: got image at master vpts %lld. vpts for picture is %lld (pts was %lld)\n",
+ cur_vpts, pic_vpts, pic_vpts);
+#endif
- /*
- * here it is - the big video output loop
- */
+ this->num_frames_delivered++;
- while ( this->video_loop_running ) {
+ diff = pic_vpts - cur_vpts;
+ frames_to_skip = ((-1 * diff) / img->duration + 3) * 2;
- /*
- * wait until it's time to display a frame
- */
-
- pause ();
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: delivery diff : %lld, current vpts is %lld\n",
+ diff, cur_vpts);
+#endif
- 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);
- }
-
- /*
- * now, look at the frame queue and decide which frame to display
- * or generate still frames if no frames are available
- */
+ if (img->display_locked) {
+ printf ("video_out: ALERT! frame is already locked for displaying\n");
+ return frames_to_skip;
+ }
- xine_profiler_start_count (prof_video_out);
+ if (cur_vpts>0) {
- cur_pts = this->metronom->get_current_time (this->metronom);
+ if (diff<(-1 * img->duration) && img->drawn != 2 ) {
+ this->num_frames_discarded++;
#ifdef VIDEO_OUT_LOG
- printf ("video_out : video loop iteration at audio pts %d\n", cur_pts);
+ printf ("video_out: frame rejected, %d frames to skip\n", frames_to_skip);
#endif
-
- img = this->display_img_buf_queue->first;
- /* update timer for inactivity flush */
- if( img ) {
- this->last_draw_vpts = cur_pts;
- } else {
- /* start timer when decoder receives the first packet */
- if( !this->last_draw_vpts && this->decoder_started_flag )
- this->last_draw_vpts = cur_pts;
-
- if( this->last_draw_vpts && (cur_pts - this->last_draw_vpts) > (8 * this->pts_per_frame) ) {
-#ifdef VIDEO_OUT_LOG
- printf("video_out : sending decoder flush due to inactivity\n");
-#endif
- video_out_send_decoder_flush( this->xine->video_fifo );
- this->last_draw_vpts = cur_pts;
- flush_sent = 1;
- }
+ pthread_mutex_lock (&img->mutex);
+ img->display_locked = 0;
+ pthread_mutex_unlock (&img->mutex);
+
+ vo_frame_displayed (img);
+
+ this->last_frame = img;
+
+ return frames_to_skip;
+
}
-
-
+ } /* else: we are probably in precaching mode */
+
+ if (!img->bad_frame) {
/*
- * throw away expired frames
+ * put frame into FIFO-Buffer
*/
- diff = 1000000;
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: frame is ok => appending to display buffer\n");
+#endif
+
+ this->last_frame = img;
+
+ pthread_mutex_lock (&img->mutex);
+ img->display_locked = 1;
+ pthread_mutex_unlock (&img->mutex);
+
+ vo_append_to_img_buf_queue (this->display_img_buf_queue, img);
+
+ } else {
+ this->num_frames_skipped++;
+
+ pthread_mutex_lock (&img->mutex);
+ img->display_locked = 0;
+ pthread_mutex_unlock (&img->mutex);
+
+ vo_frame_displayed (img);
+ }
+
+ /*
+ * performance measurement
+ */
+
+ if (this->num_frames_delivered>199) {
+ LOG_MSG_STDERR(this->xine,
+ _("%d frames delivered, %d frames skipped, %d frames discarded\n"),
+ this->num_frames_delivered,
+ this->num_frames_skipped, this->num_frames_discarded);
+
+ this->num_frames_delivered = 0;
+ this->num_frames_discarded = 0;
+ this->num_frames_skipped = 0;
+ }
+
+ return frames_to_skip;
+}
+
+static void vo_frame_free (vo_frame_t *img) {
+
+ pthread_mutex_lock (&img->mutex);
+ img->decoder_locked = 0;
+
+ if (!img->display_locked && !img->driver_locked ) {
+ vos_t *this = (vos_t *) img->instance;
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
+ }
+
+ pthread_mutex_unlock (&img->mutex);
+}
+
+
+
+/*
+ *
+ * video out loop related functions
+ *
+ */
+
+static void expire_frames (vos_t *this, int64_t cur_vpts) {
+
+ int64_t pts;
+ int64_t diff;
+ vo_frame_t *img;
+
+ img = this->display_img_buf_queue->first;
+
+ /*
+ * throw away expired frames
+ */
+
+ diff = 1000000; /* always enter the while-loop */
- while (img && (diff >this->pts_per_half_frame)) {
- pts = img->PTS;
- diff = cur_pts - pts;
- absdiff = abs(diff);
+ while (img && (diff > img->duration)) {
+ pts = img->vpts;
+ diff = cur_vpts - pts;
- if (diff >this->pts_per_half_frame) {
- LOG_MSG(this->xine, _("video_out : throwing away image with pts %d because "
- "it's too old (diff : %d > %d).\n"),
- pts, diff, this->pts_per_half_frame);
+ if (diff > img->duration) {
+ LOG_MSG(this->xine,
+ _("video_out: throwing away image with pts %lld because "
+ "it's too old (diff : %lld).\n"), pts, diff);
- this->num_frames_discarded++;
+ this->num_frames_discarded++;
- img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+ img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
- /*
- * last frame? back it up for
- * still frame creation
- */
+ /*
+ * last frame? back it up for
+ * still frame creation
+ */
- if (!this->display_img_buf_queue->first) {
+ if (!this->display_img_buf_queue->first) {
- if (img_backup) {
- pthread_mutex_lock (&img_backup->mutex);
+ if (this->img_backup) {
+ pthread_mutex_lock (&this->img_backup->mutex);
#ifdef VIDEO_OUT_LOG
- printf("video_out : overwriting frame backup\n");
+ printf("video_out: overwriting frame backup\n");
#endif
- 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;
- backup_is_logo = 0;
- } else {
- pthread_mutex_lock (&img->mutex);
-
- img->display_locked = 0;
+ this->img_backup->display_locked = 0;
if (!img->decoder_locked)
- vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
-
- pthread_mutex_unlock (&img->mutex);
+ vo_append_to_img_buf_queue (this->free_img_buf_queue,
+ this->img_backup);
+
+ pthread_mutex_unlock (&this->img_backup->mutex);
}
-
- img = this->display_img_buf_queue->first;
+ printf("video_out: possible still frame (old)\n");
+
+ /* we must not clear display_locked from img_backup.
+ without it decoder may try to free our backup. */
+ this->img_backup = img;
+ this->backup_is_logo = 0;
+ } 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);
}
- }
+
+ img = this->display_img_buf_queue->first;
+ }
+ }
- /*
- * still frame detection:
- */
+}
+
+static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) {
+
+ vo_frame_t *img;
+
+ img = this->display_img_buf_queue->first;
+
+ /*
+ * still frame detection:
+ */
- /* no frame? => still frame detection */
+ /* no frame? => still frame detection */
- if (!img) {
+ if (!img) {
#ifdef VIDEO_OUT_LOG
- printf ("video_out : no frame\n");
+ printf ("video_out: no frame\n");
#endif
- /*
- * display logo ?
- */
- if (!this->video_opened && (!img_backup || !backup_is_logo)) {
+ /*
+ * display logo ?
+ */
+ if (!this->video_opened && (!this->img_backup || !this->backup_is_logo)) {
- if (img_backup) {
- pthread_mutex_lock (&img_backup->mutex);
+ if (this->img_backup) {
+ pthread_mutex_lock (&this->img_backup->mutex);
#ifdef VIDEO_OUT_LOG
- printf("video_out : overwriting frame backup\n");
+ printf("video_out: overwriting frame backup\n");
#endif
- img_backup->display_locked = 0;
- if (!img_backup->decoder_locked)
- vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup);
+ this->img_backup->display_locked = 0;
+ if (!this->img_backup->decoder_locked)
+ vo_append_to_img_buf_queue (this->free_img_buf_queue,
+ this->img_backup);
- pthread_mutex_unlock (&img_backup->mutex);
- }
+ pthread_mutex_unlock (&this->img_backup->mutex);
+ }
- printf("video_out : copying logo image\n");
+ printf("video_out: copying logo image\n");
- img_backup = vo_get_frame (this, this->logo_w, this->logo_h,
- 42, IMGFMT_YUY2, 6000, VO_BOTH_FIELDS);
-
- img_backup->decoder_locked = 0;
- img_backup->display_locked = 1;
- img_backup->driver_locked = 0;
-
- xine_fast_memcpy(img_backup->base[0], this->logo_yuy2,
- this->logo_w*this->logo_h*2);
-
- /* this shouldn't be needed, duplicate_frame will call
- img->copy for us. [mf]
- if (img_backup->copy) {
- int height = this->logo_h;
- int stride = this->logo_w;
- uint8_t* src[3];
-
- src[0] = img_backup->base[0];
-
- while ((height -= 16) >= 0) {
- img_backup->copy(img_backup, src);
- src[0] += 32 * stride;
- }
- }
- */
-
- backup_is_logo = 1;
- }
+ this->img_backup = vo_get_frame (&this->vo, this->logo_w, this->logo_h,
+ 42, IMGFMT_YUY2, VO_BOTH_FIELDS);
+ this->img_backup->decoder_locked = 0;
+ this->img_backup->display_locked = 1;
+ this->img_backup->driver_locked = 0;
+ this->img_backup->duration = 10000;
- if (img_backup) {
+ xine_fast_memcpy(this->img_backup->base[0], this->logo_yuy2,
+ this->logo_w*this->logo_h*2);
- /*
- * 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);
- /* using abs will avoid problems if metronom gets updated */
- diff = abs(cur_pts - pts);
-
- } while (diff < 2 * this->pts_per_frame) ;
+ this->backup_is_logo = 1;
+ }
- /* if some frame arrived dont generate still */
- if( this->display_img_buf_queue->first ) {
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
+ if (this->img_backup) {
#ifdef VIDEO_OUT_LOG
- printf("video_out : generating still frame (cur_pts = %d) \n", cur_pts);
+ printf("video_out: generating still frame (cur_vpts = %lld) \n",
+ cur_vpts);
#endif
- /* keep playing still frames */
- img = this->duplicate_frame( this, img_backup );
- img->display_locked = 1;
+ /* keep playing still frames */
+ img = this->vo.duplicate_frame (&this->vo, this->img_backup );
+ img->display_locked = 1;
- img->PTS = cur_pts;
- diff = 0;
+ do {
+ this->metronom->got_video_frame(this->metronom, img);
+ } while (img->vpts < cur_vpts);
- } else {
+ return img;
+
+ } else {
#ifdef VIDEO_OUT_LOG
- printf ("video_out : no frame, but no backup frame\n");
+ printf ("video_out: no frame, but no backup frame\n");
#endif
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
- } else {
+ return NULL;
+ }
+ } else {
- /*
- * time to display frame >img< ?
- */
+ int64_t diff;
+
+ diff = cur_vpts - img->vpts;
+
+ /*
+ * time to display frame "img" ?
+ */
#ifdef VIDEO_OUT_LOG
- printf ("video_out : diff %d\n", diff);
+ printf ("video_out: diff %lld\n", diff);
#endif
- if (diff<0) {
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
+ if (diff < 0) {
+ return 0;
+ }
- if (img_backup) {
- pthread_mutex_lock (&img_backup->mutex);
- printf("video_out : freeing frame backup\n");
+ if (this->img_backup) {
+ pthread_mutex_lock (&this->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;
- }
+ this->img_backup->display_locked = 0;
+ if( !this->img_backup->decoder_locked )
+ vo_append_to_img_buf_queue (this->free_img_buf_queue,
+ this->img_backup);
+ pthread_mutex_unlock (&this->img_backup->mutex);
+ this->img_backup = NULL;
+ }
- /*
- * last frame? make backup for possible still image
- */
- if (img && !img->next &&
- (this->xine->video_fifo->size(this->xine->video_fifo) < 10 ||
- flush_sent || this->xine->video_in_discontinuity) ) {
+ /*
+ * last frame? make backup for possible still image
+ */
+ if (img && !img->next &&
+ (this->xine->video_fifo->size(this->xine->video_fifo) < 10
+ || this->xine->video_in_discontinuity) ) {
- printf("video_out : possible still frame (fifosize = %d, flushsent=%d)\n",
- this->xine->video_fifo->size(this->xine->video_fifo), flush_sent);
+ printf ("video_out: possible still frame (fifosize = %d)\n",
+ this->xine->video_fifo->size(this->xine->video_fifo));
- img_backup = this->duplicate_frame(this, img);
- backup_is_logo = 0;
- }
+ this->img_backup = this->vo.duplicate_frame (&this->vo, img);
+ this->backup_is_logo = 0;
+ }
- flush_sent = 0;
-
- /*
- * remove frame from display queue and show it
- */
+ /*
+ * remove frame from display queue and show it
+ */
- img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+ img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
- if (!img) {
- xine_profiler_stop_count (prof_video_out);
- continue;
- }
- }
+ return img;
+ }
+}
+
+static void overlay_and_display_frame (vos_t *this,
+ vo_frame_t *img) {
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: displaying image with vpts = %lld\n",
+ img->vpts);
+#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");
+#endif
+
+ img->display_locked = 0;
+ pthread_mutex_unlock (&img->mutex);
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: passing to video driver image with pts = %lld\n",
+ img->vpts);
+#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,
+ this->driver, img,
+ this->video_loop_running && this->overlay_enabled);
+ }
+
+ this->driver->display_frame (this->driver, img);
+}
+
+static void *video_out_loop (void *this_gen) {
+
+ int64_t vpts, diff;
+ vo_frame_t *img;
+ vos_t *this = (vos_t *) this_gen;
+ int64_t frame_duration, next_frame_pts;
+ int64_t usec_to_sleep;
+
+ /*
+ * here it is - the heart of xine (or rather: one of the hearts
+ * of xine) : the video output loop
+ */
+
+ frame_duration = 1500; /* default */
+ next_frame_pts = 0;
+
+#ifdef VIDEO_OUT_LOG
+ printf ("video_out: loop starting...\n");
+#endif
+
+ while ( this->video_loop_running ) {
/*
- * from this point on, img must be a valid frame for
- * overlay and output
+ * get current time and find frame to display
*/
+ vpts = this->metronom->get_current_time (this->metronom);
#ifdef VIDEO_OUT_LOG
- printf ("video_out : displaying image with pts = %d (diff=%d)\n", pts, diff);
+ printf ("video_out: loop iteration at %lld\n", vpts);
#endif
+ expire_frames (this, vpts);
+ img = get_next_frame (this, vpts);
- pthread_mutex_lock (&img->mutex);
- img->driver_locked = 1;
+ /*
+ * if we have found a frame, display it
+ */
+
+ if (img)
+ overlay_and_display_frame (this, img);
+
+ /*
+ * if we haven't heared from the decoder for some time
+ * flush it
+ */
+
+ diff = vpts - this->last_delivery_pts;
+ if (diff > 30000) {
+ if (this->xine->cur_video_decoder_plugin) {
+ this->xine->cur_video_decoder_plugin->flush(this->xine->cur_video_decoder_plugin);
#ifdef VIDEO_OUT_LOG
- if (!img->display_locked)
- printf ("video_out : ALERT! frame was not locked for display queue\n");
+ printf ("video_out: flushing current video decoder plugin\n");
#endif
- img->display_locked = 0;
- pthread_mutex_unlock (&img->mutex);
+ }
+ }
+
+ /*
+ * wait until it's time to display next frame
+ */
+
+ if (img)
+ frame_duration = img->duration;
+
+ next_frame_pts += frame_duration;
#ifdef VIDEO_OUT_LOG
- printf ("video_out : passing to video driver, image with pts = %d\n", pts);
+ printf ("video_out: next_frame_pts is %lld\n", next_frame_pts);
#endif
+
+ do {
+ vpts = this->metronom->get_current_time (this->metronom);
- if (this->overlay_source) {
- /* This is the only way for the overlay manager to get pts values
- * for flushing it's buffers. So don't remove it! */
- xine_profiler_start_count (prof_spu_blend);
+ usec_to_sleep = (next_frame_pts - vpts) * 100 / 9;
- this->overlay_source->multiple_overlay_blend (this->overlay_source, img->PTS,
- this->driver, img,
- this->video_loop_running && this->overlay_enabled);
- xine_profiler_stop_count (prof_spu_blend);
- }
-
- this->driver->display_frame (this->driver, img);
+ printf ("video_out: %lld usec to sleep at master vpts %lld\n",
+ usec_to_sleep, vpts);
+
+ if (usec_to_sleep>0)
+ xine_usec_sleep (usec_to_sleep);
- xine_profiler_stop_count (prof_video_out);
+ } while (usec_to_sleep > 0);
}
+
/*
* throw away undisplayed frames
*/
@@ -596,29 +716,32 @@ static void *video_out_loop (void *this_gen) {
img = this->display_img_buf_queue->first;
}
- if( img_backup ) {
- pthread_mutex_lock (&img_backup->mutex);
+ if (this->img_backup) {
+ pthread_mutex_lock (&this->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);
+ this->img_backup->display_locked = 0;
+ if (!this->img_backup->decoder_locked)
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, this->img_backup);
- pthread_mutex_unlock (&img_backup->mutex);
+ pthread_mutex_unlock (&this->img_backup->mutex);
}
pthread_exit(NULL);
}
-static uint32_t vo_get_capabilities (vo_instance_t *this) {
+static uint32_t vo_get_capabilities (vo_instance_t *this_gen) {
+ vos_t *this = (vos_t *) this_gen;
return this->driver->get_capabilities (this->driver);
}
-static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) {
+static vo_frame_t * vo_duplicate_frame( vo_instance_t *this_gen, vo_frame_t *img ) {
+
vo_frame_t *dupl;
- int image_size;
+ /* vos_t *this = (vos_t *) this_gen; */
+ int image_size;
- dupl = vo_get_frame( this, img->width, img->height, img->ratio,
- img->format, img->duration, VO_BOTH_FIELDS );
+ dupl = vo_get_frame (this_gen, img->width, img->height, img->ratio,
+ img->format, VO_BOTH_FIELDS );
pthread_mutex_lock (&dupl->mutex);
@@ -643,7 +766,10 @@ static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) {
}
dupl->bad_frame = 0;
- dupl->PTS = dupl->SCR = 0;
+ dupl->pts = 0;
+ dupl->vpts = 0;
+ dupl->scr = 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 */
@@ -683,14 +809,18 @@ static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) {
return dupl;
}
-static void vo_open (vo_instance_t *this) {
+static void vo_open (vo_instance_t *this_gen) {
+
+ vos_t *this = (vos_t *) this_gen;
- this->decoder_started_flag = 0;
this->video_opened = 1;
+ this->last_delivery_pts = 0;
}
-static void vo_close (vo_instance_t *this) {
-
+static void vo_close (vo_instance_t *this_gen) {
+
+ vos_t *this = (vos_t *) this_gen;
+
/* this will make sure all hide events were processed */
if (this->overlay_source)
this->overlay_source->flush_events (this->overlay_source);
@@ -698,7 +828,8 @@ static void vo_close (vo_instance_t *this) {
this->video_opened = 0;
}
-static void vo_free_img_buffers (vo_instance_t *this) {
+static void vo_free_img_buffers (vo_instance_t *this_gen) {
+ vos_t *this = (vos_t *) this_gen;
vo_frame_t *img;
while (this->free_img_buf_queue->first) {
@@ -712,163 +843,45 @@ static void vo_free_img_buffers (vo_instance_t *this) {
}
}
-static void vo_exit (vo_instance_t *this) {
+static void vo_exit (vo_instance_t *this_gen) {
+
+ vos_t *this = (vos_t *) this_gen;
printf ("video_out: vo_exit...\n");
if (this->video_loop_running) {
void *p;
this->video_loop_running = 0;
- this->video_paused = 0;
pthread_join (this->video_thread, &p);
}
- vo_free_img_buffers (this);
+ vo_free_img_buffers (this_gen);
this->driver->exit (this->driver);
printf ("video_out: vo_exit... done\n");
}
-static void vo_frame_displayed (vo_frame_t *img) {
-
- pthread_mutex_lock (&img->mutex);
-
- img->driver_locked = 0;
-
- if (!img->decoder_locked) {
- vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img);
- }
-
- pthread_mutex_unlock (&img->mutex);
-}
-
-static void vo_frame_free (vo_frame_t *img) {
-
- pthread_mutex_lock (&img->mutex);
- img->decoder_locked = 0;
-
- if (!img->display_locked && !img->driver_locked ) {
- vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img);
- }
-
- pthread_mutex_unlock (&img->mutex);
-}
-
-static vo_frame_t *vo_get_last_frame (vo_instance_t *this) {
+static vo_frame_t *vo_get_last_frame (vo_instance_t *this_gen) {
+ vos_t *this = (vos_t *) this_gen;
return this->last_frame;
}
-static int vo_frame_draw (vo_frame_t *img) {
-
- vo_instance_t *this = img->instance;
- int32_t diff;
- uint32_t cur_vpts;
- uint32_t pic_vpts ;
- int frames_to_skip;
-
- 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",
- img, pic_vpts, img->PTS);
-#endif
-
- img->PTS = pic_vpts;
- this->num_frames_delivered++;
-
- cur_vpts = this->metronom->get_current_time(this->metronom);
- this->last_draw_vpts = cur_vpts;
-
- 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);
-#endif
-
- if (img->display_locked) {
- LOG_MSG(this->xine, _("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) && img->drawn != 2 ) {
-
- this->num_frames_discarded++;
-#ifdef VIDEO_OUT_LOG
- printf ("video_out : frame rejected, %d frames to skip\n", frames_to_skip);
-#endif
-
- LOG_MSG(this->xine, _("video_out: rejected, %d frames to skip\n"), frames_to_skip);
-
- pthread_mutex_lock (&img->mutex);
- img->display_locked = 0;
- pthread_mutex_unlock (&img->mutex);
-
- vo_frame_displayed (img);
-
- this->last_frame = img;
-
- return frames_to_skip;
-
- }
- } /* else: we are probably in precaching mode */
-
- if (!img->bad_frame) {
- /*
- * put frame into FIFO-Buffer
- */
-
-#ifdef VIDEO_OUT_LOG
- printf ("video_out : frame is ok => appending to display buffer\n");
-#endif
-
- this->last_frame = img;
-
- pthread_mutex_lock (&img->mutex);
- img->display_locked = 1;
- pthread_mutex_unlock (&img->mutex);
-
- vo_append_to_img_buf_queue (this->display_img_buf_queue, img);
-
- } else {
- this->num_frames_skipped++;
-
- pthread_mutex_lock (&img->mutex);
- img->display_locked = 0;
- pthread_mutex_unlock (&img->mutex);
-
- vo_frame_displayed (img);
- }
-
- /*
- * performance measurement
- */
-
- if (this->num_frames_delivered>199) {
- LOG_MSG_STDERR(this->xine,
- _("%d frames delivered, %d frames skipped, %d frames discarded\n"),
- this->num_frames_delivered, this->num_frames_skipped, this->num_frames_discarded);
+/*
+ * overlay stuff
+ */
- this->num_frames_delivered = 0;
- this->num_frames_discarded = 0;
- this->num_frames_skipped = 0;
- }
-
- return frames_to_skip;
+static video_overlay_instance_t *vo_get_overlay_instance (vo_instance_t *this_gen) {
+ vos_t *this = (vos_t *) this_gen;
+ return this->overlay_source;
}
-static void vo_enable_overlay (vo_instance_t *this, int overlay_enabled) {
+static void vo_enable_overlay (vo_instance_t *this_gen, int overlay_enabled) {
+ vos_t *this = (vos_t *) this_gen;
this->overlay_enabled = overlay_enabled;
}
-static void vo_decoder_started (vo_instance_t *this) {
- this->decoder_started_flag = 1;
-}
-
static uint16_t gzread_i16(gzFile *fp) {
uint16_t ret;
ret = gzgetc(fp) << 8 ;
@@ -880,28 +893,28 @@ static uint16_t gzread_i16(gzFile *fp) {
vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
- vo_instance_t *this;
+ vos_t *this;
int i;
char pathname[LOGO_PATH_MAX];
pthread_attr_t pth_attrs;
int err;
gzFile *fp;
+ this = xine_xmalloc (sizeof (vos_t)) ;
- this = xine_xmalloc (sizeof (vo_instance_t)) ;
this->driver = driver;
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->vo.open = vo_open;
+ this->vo.get_frame = vo_get_frame;
+ this->vo.duplicate_frame = vo_duplicate_frame;
+ this->vo.get_last_frame = vo_get_last_frame;
+ this->vo.close = vo_close;
+ this->vo.exit = vo_exit;
+ this->vo.get_capabilities = vo_get_capabilities;
+ this->vo.enable_ovl = vo_enable_overlay;
+ this->vo.get_overlay_instance = vo_get_overlay_instance;
this->num_frames_delivered = 0;
this->num_frames_skipped = 0;
@@ -909,9 +922,9 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
this->free_img_buf_queue = vo_new_img_buf_queue ();
this->display_img_buf_queue = vo_new_img_buf_queue ();
this->video_loop_running = 0;
- this->video_paused = 0;
- this->pts_per_frame = 6000;
- this->pts_per_half_frame = 3000;
+
+ this->img_backup = NULL;
+ this->backup_is_logo = 0;
this->overlay_source = video_overlay_new_instance();
this->overlay_source->init (this->overlay_source);
@@ -922,7 +935,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
img = driver->alloc_frame (driver) ;
- img->instance = this;
+ img->instance = &this->vo;
img->free = vo_frame_free ;
img->displayed = vo_frame_displayed;
img->draw = vo_frame_draw;
@@ -961,7 +974,6 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
*/
this->video_loop_running = 1;
- this->decoder_started_flag = 0;
this->video_opened = 0;
pthread_attr_init(&pth_attrs);
@@ -976,10 +988,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) {
printf (_("video_out: sorry, this should not happen. please restart xine.\n"));
exit(1);
} else
- LOG_MSG(this->xine, _("video_out : thread created\n"));
+ LOG_MSG(this->xine, _("video_out: thread created\n"));
- return this;
+ return &this->vo;
}
-
-
-