1 /*
2  * Copyright (C) 2000-2020 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * frame allocation / queuing / scheduling / output functions
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <signal.h>
28 #include <sys/time.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pthread.h>
34 #include <inttypes.h>
35 #include <errno.h>
36 #include <sys/time.h>
37 
38 #define XINE_ENABLE_EXPERIMENTAL_FEATURES
39 
40 #define LOG_MODULE "video_out"
41 #define LOG_VERBOSE
42 /*
43 #define LOG
44 #define LOG_FLUSH
45 */
46 
47 #include <xine/xine_internal.h>
48 #include <xine/video_out.h>
49 #include <xine/metronom.h>
50 #include <xine/xineutils.h>
51 #include <yuv2rgb.h>
52 
53 #include "xine_private.h"
54 
55 #define NUM_FRAME_BUFFERS          15
56 #define DEFAULT_FRAME_DURATION   3000    /* 30 frames per second */
57 
58 /* wait this delay if the first frame is still referenced */
59 #define FIRST_FRAME_POLL_DELAY   3000
60 #define FIRST_FRAME_MAX_POLL       10    /* poll n times at most */
61 
62 /*
63 #define ADD_KEYFRAME_INDEX
64 */
65 
66 /* experimental optimization: try to allocate frames from free queue
67  * in the same format as requested (avoid unnecessary free/alloc in
68  * vo driver). up to 25% less cpu load using deinterlace with film mode.
69  */
70 #define EXPERIMENTAL_FRAME_QUEUE_OPTIMIZATION 1
71 
72 typedef struct vos_grab_video_frame_s vos_grab_video_frame_t;
73 struct vos_grab_video_frame_s {
74   xine_grab_video_frame_t grab_frame;
75 
76   vos_grab_video_frame_t *next;
77   int finished;
78   xine_video_port_t *video_port;
79   vo_frame_t *vo_frame;
80   yuv2rgb_factory_t *yuv2rgb_factory;
81   yuv2rgb_t *yuv2rgb;
82   int vo_width, vo_height;
83   int grab_width, grab_height;
84   int y_stride, uv_stride;
85   int img_size;
86   uint8_t *img;
87 };
88 
89 
90 typedef struct {
91 
92   xine_video_port_t         vo; /* public part */
93 
94   vo_driver_t              *driver;
95   pthread_mutex_t           driver_lock;
96   xine_private_t           *xine;
97   metronom_clock_t         *clock;
98 
99 #define STREAMS_DEFAULT_SIZE 32
100   int                       num_null_streams;
101   int                       num_anon_streams;
102   int                       num_streams;
103   int                       streams_size;
104   xine_stream_private_t   **streams, *streams_default[STREAMS_DEFAULT_SIZE];
105   xine_rwlock_t             streams_lock;
106 
107   struct {
108     pthread_mutex_t         mutex;
109     pthread_cond_t          not_empty;
110     vo_frame_t             *first;
111     vo_frame_t            **add;
112     int                     num_buffers;
113     int                     num_buffers_max;
114     int                     locked_for_read;
115   } free_queue;
116 
117   struct {
118     pthread_mutex_t         mutex;
119     pthread_cond_t          not_empty;
120     pthread_cond_t          done_flushing;
121     vo_frame_t             *first;
122     vo_frame_t            **add;
123     int                     num_buffers;
124     int                     locked_for_read;
125     /* The flush protocol. */
126     int                     discard_frames;
127     int                     flushed;
128     /* Snapshot of rp.ready_num. */
129     int                     flush_extra;
130     int                     num_flush_waiters;
131     /* frame stream refs.
132      * we need to ref a stream for at least as long as it has frames flying around.
133      * at first sight, it would be nice to unref as early as puossible, so the
134      * stream can dispose itself. however, that would be a performance killer.
135      * also, it may not have the desired effect when the stream itself gets reused,
136      * and/or some frames are held by driver and this->grab.last_frame.
137      * instead, let the natural flow clean up for us in vo_display_reref_append (),
138      * and check manually now and then while running idle. */
139     vo_frame_t            **frames;
140     xine_stream_private_t **img_streams;
141   } display_queue;
142 
143   /* Render thread privates. Other threads may _read_ integers, without freshness
144    * guarantee. */
145   struct {
146     /* Optimization: keep video decoder from interfering with output timing.
147      * Employ a separate mutex less frame queue private to the render thread.
148      * Fetch the entire shared queue into it when flushing, or when running
149      * down to less than 2 frames. This way we can still set frame.future_frame.
150      * Also, do that after time critical stuff, if possible. */
151     vo_frame_t             *ready_first;
152     vo_frame_t            **ready_add;
153     int                     ready_num;
154     /* Adaptive redraw needed polling. */
155     int                     poll_time;
156     int                     poll_limit;
157     int                     poll_num;
158     /* Output loop iterations, total and without a frame to display. */
159     int                     wakeups_total;
160     int                     wakeups_early;
161     /* Snapshot of display_queue.num_flush_waiters. */
162     int                     need_flush_signal;
163     /* Filler frame during forward seek. */
164     vo_frame_t             *last_flushed;
165     /* Wakeup time. */
166     struct timespec         now;
167     int                     speed;
168   } rp;
169 
170   /* Get grab_lock when
171    *  - accessing grab queue,
172    *  - setting last_frame, and
173    *  - reading last_frame from outside the render thread.
174    */
175   struct {
176     pthread_mutex_t         lock;
177     pthread_cond_t          wake;
178     vos_grab_video_frame_t *request;
179     vo_frame_t             *last_frame;
180   } grab;
181 
182   uint32_t                  video_loop_running:1;
183   uint32_t                  video_opened:1;
184 
185   uint32_t                  overlay_enabled:1;
186 
187   uint32_t                  warn_threshold_event_sent:1;
188 
189   /* do we true real-time output or is this a grab only instance ? */
190   uint32_t                  grab_only:1;
191 
192   uint32_t                  redraw_needed:3;
193 
194   pthread_t                 video_thread;
195 
196   int                       num_frames_delivered;
197   int                       num_frames_skipped;
198   int                       num_frames_discarded;
199   int                       num_frames_burst;
200 
201   /* threshold for sending XINE_EVENT_DROPPED_FRAMES */
202   int                       warn_skipped_threshold;
203   int                       warn_discarded_threshold;
204   int                       warn_threshold_exceeded;
205 
206   int                       disable_decoder_flush_from_video_out;
207 
208   /* pts value when decoder delivered last video frame */
209   int64_t                   last_delivery_pts;
210 
211   video_overlay_manager_t  *overlay_source;
212 
213   extra_info_t             *extra_info_base; /* used to free mem chunk */
214 
215   int                       current_width, current_height;
216   int64_t                   current_duration;
217 
218   int                       frame_drop_limit_max;
219   int                       frame_drop_limit;
220   int                       frame_drop_cpt;
221   int                       frame_drop_suggested;
222 
223   int                       crop_left, crop_right, crop_top, crop_bottom;
224 
225   struct {
226     pthread_mutex_t         mutex;
227     pthread_cond_t          wake;
228     pthread_cond_t          done_stepping;
229     int                     draw;
230     int                     speed;
231     int                     step;
232   } trigger_drawing;
233 
234 #ifdef ADD_KEYFRAME_INDEX
235   int                       keyframe_mode;
236 #endif
237 
238   /* frames usage stats */
239   int                       frames_total;
240   int                       frames_extref;
241   int                       frames_peak_used;
242 } vos_t;
243 
244 
245 /********************************************************************
246  * streams register.                                                *
247  * Reading is way more speed relevant here.                         *
248  *******************************************************************/
249 
vo_streams_open(vos_t * this)250 static void vo_streams_open (vos_t *this) {
251 #ifndef HAVE_ZERO_SAFE_MEM
252   this->num_null_streams   = 0;
253   this->num_anon_streams   = 0;
254   this->num_streams        = 0;
255   this->streams_default[0] = NULL;
256 #endif
257   this->streams_size = STREAMS_DEFAULT_SIZE;
258   this->streams      = &this->streams_default[0];
259   xine_rwlock_init_default (&this->streams_lock);
260 }
261 
vo_streams_close(vos_t * this)262 static void vo_streams_close (vos_t *this) {
263   xine_rwlock_destroy (&this->streams_lock);
264   if (this->streams != &this->streams_default[0])
265     free (this->streams);
266 #if 0 /* not yet needed */
267   this->streams          = NULL;
268   this->num_null_streams = 0;
269   this->num_anon_streams = 0;
270   this->num_streams      = 0;
271   this->streams_size     = 0;
272 #endif
273 }
274 
vo_streams_register(vos_t * this,xine_stream_private_t * s)275 static void vo_streams_register (vos_t *this, xine_stream_private_t *s) {
276   xine_rwlock_wrlock (&this->streams_lock);
277   if (!s) {
278     this->num_null_streams++;
279   } else if (&s->s == XINE_ANON_STREAM) {
280     this->num_anon_streams++;
281   } else do {
282     xine_stream_private_t **a = this->streams;
283     if (this->num_streams + 2 > this->streams_size) {
284       xine_stream_private_t **n = malloc ((this->streams_size + 32) * sizeof (void *));
285       if (!n)
286         break;
287       memcpy (n, a, this->streams_size * sizeof (void *));
288       this->streams = n;
289       if (a != &this->streams_default[0])
290         free (a);
291       a = n;
292       this->streams_size += 32;
293     }
294     a[this->num_streams++] = s;
295     a[this->num_streams] = NULL;
296   } while (0);
297   xine_rwlock_unlock (&this->streams_lock);
298 }
299 
vo_streams_unregister(vos_t * this,xine_stream_private_t * s)300 static void vo_streams_unregister (vos_t *this, xine_stream_private_t *s) {
301   xine_rwlock_wrlock (&this->streams_lock);
302   if (!s) {
303     this->num_null_streams--;
304   } else if (&s->s == XINE_ANON_STREAM) {
305     this->num_anon_streams--;
306   } else {
307     xine_stream_private_t **a = this->streams;
308     while (*a && (*a != s))
309       a++;
310     if (*a) {
311       do {
312         a[0] = a[1];
313         a++;
314       } while (*a);
315       this->num_streams--;
316     }
317   }
318   xine_rwlock_unlock (&this->streams_lock);
319 }
320 
321 /********************************************************************
322  * reuse frame stream refs.                                         *
323  * be the current owner of img when calling this.                   *
324  *******************************************************************/
325 
vo_reref(vos_t * this,vo_frame_t * img)326 static void vo_reref (vos_t *this, vo_frame_t *img) {
327   xine_stream_private_t **s, *olds, *news;
328   /* Paranoia? */
329   s = ((img->id >= 0) && (img->id < this->frames_total))
330     ? this->display_queue.img_streams + img->id
331     : &news;
332   news = (xine_stream_private_t *)img->stream;
333   pthread_mutex_lock (&this->display_queue.mutex);
334   olds = *s;
335   if (olds != news) {
336     *s = news;
337     pthread_mutex_unlock (&this->display_queue.mutex);
338     if (news)
339       xine_refs_add (&news->refs, 1); /* this is fast. */
340     if (olds)
341       xine_refs_sub (&olds->refs, 1); /* this may involve stream dispose. */
342   } else {
343     pthread_mutex_unlock (&this->display_queue.mutex);
344   }
345 }
346 
vo_unref_list(vos_t * this,vo_frame_t * img)347 static void vo_unref_list (vos_t *this, vo_frame_t *img) {
348   xine_stream_private_t *d[128], **a = d;
349 
350   pthread_mutex_lock (&this->display_queue.mutex);
351   for (; img; img = img->next) {
352     img->stream = NULL;
353     /* Paranoia? */
354     if ((img->id >= 0) && (img->id < this->frames_total)) {
355       xine_stream_private_t **s = this->display_queue.img_streams + img->id;
356       if (*s) {
357         *a++ = *s;
358         *s = NULL;
359         if (a > d + sizeof (d) / sizeof (d[0]) - 2)
360           break;
361       }
362     }
363   }
364   pthread_mutex_unlock (&this->display_queue.mutex);
365   *a = NULL;
366 
367   for (a = d; *a; a++)
368     xine_refs_sub (&(*a)->refs, 1); /* this may involve stream dispose. */
369 }
370 
vo_unref_obsolete(vos_t * this)371 static void vo_unref_obsolete (vos_t *this) {
372   int i;
373   xine_stream_private_t *d[128], **a = d;
374 
375   xine_rwlock_rdlock (&this->streams_lock);
376   pthread_mutex_lock (&this->display_queue.mutex);
377 
378   for (i = 0; i < this->frames_total; i++) {
379     vo_frame_t *f;
380     xine_stream_private_t *img_stream = this->display_queue.img_streams[i], **open_stream;
381     if (!img_stream)
382       continue;
383     for (open_stream = this->streams; *open_stream; open_stream++) {
384       if (img_stream == *open_stream)
385         break;
386     }
387     if (*open_stream)
388       continue;
389     f = this->display_queue.frames[i];
390     if (pthread_mutex_trylock (&f->mutex))
391       continue;
392     if ((f->lock_counter != 0) || (f->id != i)) {
393       pthread_mutex_unlock (&f->mutex);
394       continue;
395     }
396     pthread_mutex_unlock (&f->mutex);
397     this->display_queue.img_streams[i] = NULL;
398     *a++ = img_stream;
399     if (a > d + sizeof (d) / sizeof (d[0]) - 2)
400       break;
401   }
402   *a = NULL;
403 
404   pthread_mutex_unlock (&this->display_queue.mutex);
405   xine_rwlock_unlock (&this->streams_lock);
406 
407   if (a > d) {
408     for (a = d; *a; a++)
409       xine_refs_sub (&(*a)->refs, 1);
410     xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
411       "video_out: freed %d obsolete stream refs.\n", (int)(a - d));
412   }
413 }
414 
415 /********************************************************************
416  * frame queue (fifo)                                               *
417  *******************************************************************/
418 
vo_free_queue_open(vos_t * this)419 static void vo_free_queue_open (vos_t *this) {
420 #ifndef HAVE_ZERO_SAFE_MEM
421   this->free_queue.first           = NULL;
422   this->free_queue.num_buffers     = 0;
423   this->free_queue.num_buffers_max = 0;
424   this->free_queue.locked_for_read = 0;
425 #endif
426   this->free_queue.add             = &this->free_queue.first;
427   pthread_mutex_init (&this->free_queue.mutex, NULL);
428   pthread_cond_init  (&this->free_queue.not_empty, NULL);
429 }
430 
vo_display_queue_open(vos_t * this)431 static void vo_display_queue_open (vos_t *this) {
432 #ifndef HAVE_ZERO_SAFE_MEM
433   this->display_queue.first             = NULL;
434   this->display_queue.num_buffers       = 0;
435   this->display_queue.locked_for_read   = 0;
436   this->display_queue.discard_frames    = 0;
437   this->display_queue.flushed           = 0;
438   this->display_queue.flush_extra       = 0;
439   this->display_queue.num_flush_waiters = 0;
440 #endif
441   this->display_queue.add               = &this->display_queue.first;
442   pthread_mutex_init (&this->display_queue.mutex, NULL);
443   pthread_cond_init  (&this->display_queue.not_empty, NULL);
444   pthread_cond_init  (&this->display_queue.done_flushing, NULL);
445 }
446 
vo_free_queue_close(vos_t * this)447 static void vo_free_queue_close (vos_t *this) {
448 #if 0 /* not yet needed */
449   this->display_queue.first             = NULL;
450   this->display_queue.num_buffers       = 0;
451   this->display_queue.locked_for_read   = 0;
452   this->display_queue.discard_frames    = 0;
453   this->display_queue.flushed           = 0;
454   this->display_queue.flush_extra       = 0;
455   this->display_queue.num_flush_waiters = 0;
456   this->display_queue.add               = &this->display_queue.first;
457 #endif
458   pthread_mutex_destroy (&this->free_queue.mutex);
459   pthread_cond_destroy (&this->free_queue.not_empty);
460 }
461 
vo_display_queue_close(vos_t * this)462 static void vo_display_queue_close (vos_t *this) {
463 #if 0 /* not yet needed */
464   this->free_queue.first           = NULL;
465   this->free_queue.num_buffers     = 0;
466   this->free_queue.num_buffers_max = 0;
467   this->free_queue.locked_for_read = 0;
468   this->free_queue.add             = &this->free_queue.first;
469 #endif
470   pthread_mutex_destroy (&this->display_queue.mutex);
471   pthread_cond_destroy (&this->display_queue.not_empty);
472   pthread_cond_destroy (&this->display_queue.done_flushing);
473 }
474 
vo_free_queue_get_all(vos_t * this)475 static vo_frame_t *vo_free_queue_get_all (vos_t *this) {
476   vo_frame_t *list;
477 
478   pthread_mutex_lock (&this->free_queue.mutex);
479   list = this->free_queue.first;
480   this->free_queue.first = NULL;
481   this->free_queue.add   = &this->free_queue.first;
482   this->free_queue.num_buffers = 0;
483   pthread_mutex_unlock (&this->free_queue.mutex);
484   return list;
485 }
486 
vo_display_queue_get_all(vos_t * this)487 static vo_frame_t *vo_display_queue_get_all (vos_t *this) {
488   vo_frame_t *list;
489 
490   pthread_mutex_lock (&this->display_queue.mutex);
491   list = this->display_queue.first;
492   this->display_queue.first = NULL;
493   this->display_queue.add   = &this->display_queue.first;
494   this->display_queue.num_buffers = 0;
495   pthread_mutex_unlock (&this->display_queue.mutex);
496   return list;
497 }
498 
vo_dispose_list(vo_frame_t * list)499 static void vo_dispose_list (vo_frame_t *list) {
500   while (list) {
501     vo_frame_t *next = list->next;
502     list->next = NULL;
503     list->dispose (list);
504     list = next;
505   }
506 }
507 
vo_free_queue_read_lock(vos_t * this)508 static void vo_free_queue_read_lock (vos_t *this) {
509   pthread_mutex_lock (&this->free_queue.mutex);
510   this->free_queue.locked_for_read = 2;
511   pthread_mutex_unlock (&this->free_queue.mutex);
512 }
513 
vo_free_queue_read_unlock(vos_t * this)514 static void vo_free_queue_read_unlock (vos_t *this) {
515   pthread_mutex_lock (&this->free_queue.mutex);
516   this->free_queue.locked_for_read = 0;
517   if (this->free_queue.first)
518     pthread_cond_signal (&this->free_queue.not_empty);
519   pthread_mutex_unlock (&this->free_queue.mutex);
520 }
521 
vo_ticket_revoked(void * user_data,int flags)522 static void vo_ticket_revoked (void *user_data, int flags) {
523   vos_t *this = (vos_t *)user_data;
524   const char *s1 = (flags & XINE_TICKET_FLAG_ATOMIC) ? " atomic" : "";
525   const char *s2 = (flags & XINE_TICKET_FLAG_REWIRE) ? " port_rewire" : "";
526   pthread_cond_signal (&this->free_queue.not_empty);
527   xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: port ticket revoked%s%s.\n", s1, s2);
528 }
529 
vo_display_reref_append(vos_t * this,vo_frame_t * img)530 static void vo_display_reref_append (vos_t *this, vo_frame_t *img) {
531   xine_stream_private_t **s, *olds, *news;
532   /* img already enqueue? (serious leak) */
533   _x_assert (img->next == NULL);
534   img->next = NULL;
535   /* Paranoia? */
536   s = ((img->id >= 0) && (img->id < this->frames_total))
537     ? this->display_queue.img_streams + img->id
538     : &news;
539   news = (xine_stream_private_t *)img->stream;
540   pthread_mutex_lock (&this->display_queue.mutex);
541   olds = *s;
542   if (olds != news) {
543     int n;
544     *s = news;
545     if (news)
546       xine_refs_add (&news->refs, 1); /* this is fast. */
547     n = (this->display_queue.first ? this->display_queue.num_buffers : 0) + 1;
548     *(this->display_queue.add) = img;
549     this->display_queue.add    = &img->next;
550     this->display_queue.num_buffers = n;
551     if (n > this->display_queue.locked_for_read)
552       pthread_cond_signal (&this->display_queue.not_empty);
553     pthread_mutex_unlock (&this->display_queue.mutex);
554     if (olds)
555       xine_refs_sub (&olds->refs, 1); /* this may involve stream dispose. */
556   } else {
557     int n = (this->display_queue.first ? this->display_queue.num_buffers : 0) + 1;
558     *(this->display_queue.add) = img;
559     this->display_queue.add    = &img->next;
560     this->display_queue.num_buffers = n;
561     if (n > this->display_queue.locked_for_read)
562       pthread_cond_signal (&this->display_queue.not_empty);
563     pthread_mutex_unlock (&this->display_queue.mutex);
564   }
565 }
566 
vo_free_append(vos_t * this,vo_frame_t * img)567 static void vo_free_append (vos_t *this, vo_frame_t *img) {
568   int n;
569 
570   /* img already enqueue? (serious leak) */
571   _x_assert (img->next==NULL);
572 
573   pthread_mutex_lock (&this->free_queue.mutex);
574   img->next = NULL;
575   n = (this->free_queue.first ? this->free_queue.num_buffers : 0) + 1;
576   *(this->free_queue.add) = img;
577   this->free_queue.add    = &img->next;
578   this->free_queue.num_buffers = n;
579   if (n > this->free_queue.locked_for_read)
580     pthread_cond_signal (&this->free_queue.not_empty);
581   pthread_mutex_unlock (&this->free_queue.mutex);
582 }
583 
vo_free_append_list(vos_t * this,vo_frame_t * img,vo_frame_t ** add,int n)584 static void vo_free_append_list (vos_t *this, vo_frame_t *img, vo_frame_t **add, int n) {
585   if (!img)
586     return;
587 
588   pthread_mutex_lock (&this->free_queue.mutex);
589 
590   *(this->free_queue.add) = img;
591   this->free_queue.add    = add;
592 
593   n += this->free_queue.num_buffers;
594   this->free_queue.num_buffers = n;
595 
596   if (n > this->free_queue.locked_for_read)
597     pthread_cond_broadcast (&this->free_queue.not_empty);
598   pthread_mutex_unlock (&this->free_queue.mutex);
599 }
600 
vo_free_queue_pop_int(vos_t * this)601 static vo_frame_t *vo_free_queue_pop_int (vos_t *this) {
602   vo_frame_t *img;
603 
604   img = this->free_queue.first;
605   this->free_queue.first = img->next;
606   img->next = NULL;
607   if (!this->free_queue.first) {
608     this->free_queue.add = &this->free_queue.first;
609     this->free_queue.num_buffers = 0;
610   } else {
611     this->free_queue.num_buffers--;
612   }
613   return img;
614 }
615 
vo_display_queue_pop_int(vos_t * this)616 static vo_frame_t *vo_display_queue_pop_int (vos_t *this) {
617   vo_frame_t *img;
618 
619   img = this->display_queue.first;
620   this->display_queue.first = img->next;
621   img->next = NULL;
622   if (!this->display_queue.first) {
623     this->display_queue.add = &this->display_queue.first;
624     this->display_queue.num_buffers = 0;
625   } else {
626     this->display_queue.num_buffers--;
627   }
628   return img;
629 }
630 
631 static int vo_frame_dec2_lock_int (vos_t *this, vo_frame_t *img);
632 
vo_get_unblock_frame(vos_t * this)633 static vo_frame_t *vo_get_unblock_frame (vos_t *this) {
634   vo_frame_t *f, **add;
635   /* Try 1: free queue reserve. */
636   pthread_mutex_lock (&this->free_queue.mutex);
637   if (this->free_queue.first) {
638     f = vo_free_queue_pop_int (this);
639     pthread_mutex_unlock (&this->free_queue.mutex);
640     xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: got unblock frame from free queue.\n");
641     return f;
642   }
643   pthread_mutex_unlock (&this->free_queue.mutex);
644   /* Try 2: shared display queue. */
645   pthread_mutex_lock (&this->display_queue.mutex);
646   add = &this->display_queue.first;
647   while ((f = *add)) {
648     if (f->lock_counter <= 2)
649       break;
650     add = &f->next;
651   }
652   if (f) {
653     *add = f->next;
654     /* f->next = NULL; vo_frame_dec2_lock_int () does this below */
655     this->display_queue.num_buffers--;
656     if (!*add) {
657       this->display_queue.add = add;
658       /* just a safety reset */
659       if (!this->display_queue.first)
660         this->display_queue.num_buffers = 0;
661     }
662     pthread_mutex_unlock (&this->display_queue.mutex);
663     vo_frame_dec2_lock_int (this, f);
664     xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: got unblock frame from display queue.\n");
665     return f;
666   }
667   pthread_mutex_unlock (&this->display_queue.mutex);
668   return NULL;
669 }
670 
vo_free_queue_get(vos_t * this,uint32_t width,uint32_t height,double ratio,int format,int flags)671 static vo_frame_t *vo_free_queue_get (vos_t *this,
672   uint32_t width, uint32_t height, double ratio, int format, int flags) {
673   vo_frame_t *img, **add;
674 
675   (void)flags;
676   pthread_mutex_lock (&this->free_queue.mutex);
677 
678   do {
679     add = &this->free_queue.first;
680     if (this->free_queue.num_buffers > this->free_queue.locked_for_read) {
681       img = *add;
682 #if EXPERIMENTAL_FRAME_QUEUE_OPTIMIZATION
683       if (width && height) {
684         /* try to obtain a frame with the same format first.
685          * doing so may avoid unnecessary alloc/free's at the vo
686          * driver, specially when using post plugins that change
687          * format like the tvtime deinterlacer does.
688          */
689         int i = 0;
690         while (img &&
691           ((img->format != format) || (img->width != (int)width) ||
692            (img->height != (int)height) || (img->ratio != ratio))) {
693           add = &img->next;
694           img = *add;
695           i++;
696         }
697 
698         if (!img) {
699           if ((this->free_queue.num_buffers == 1) && (this->free_queue.num_buffers_max > 8)) {
700             /* only a single frame on fifo with different
701              * format -> ignore it (give another chance of a frame format hit)
702              * only if we have a lot of buffers at all.
703              */
704             lprintf("frame format mismatch - will wait another frame\n");
705           } else {
706             /* we have just a limited number of buffers or at least 2 frames
707              * on fifo but they don't match -> give up. return whatever we got.
708              */
709             add = &this->free_queue.first;
710             img = *add;
711             lprintf("frame format miss (%d/%d)\n", i, this->free_queue.num_buffers);
712           }
713         } else {
714           /* good: format match! */
715           lprintf("frame format hit (%d/%d)\n", i, this->free_queue.num_buffers);
716         }
717       }
718 #endif
719     } else {
720       img = NULL;
721     }
722     if (!img) {
723       if (this->xine->port_ticket->ticket_revoked) {
724         pthread_mutex_unlock (&this->free_queue.mutex);
725         this->xine->port_ticket->renew (this->xine->port_ticket, 1);
726         if (!(this->xine->port_ticket->ticket_revoked & XINE_TICKET_FLAG_REWIRE)) {
727           pthread_mutex_lock (&this->free_queue.mutex);
728           continue;
729         }
730         /* O dear. Port rewire ahaed. Try unblocking with regular or emergency frame. */
731         if (this->clock->speed == XINE_SPEED_PAUSE) {
732           img = vo_get_unblock_frame (this);
733           if (img)
734             return img;
735           xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: allow port rewire.\n");
736           this->xine->port_ticket->renew (this->xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
737           pthread_mutex_lock (&this->free_queue.mutex);
738           continue;
739         }
740         pthread_mutex_lock (&this->free_queue.mutex);
741       }
742       {
743         struct timespec ts = {0, 0};
744         xine_gettime (&ts);
745         ts.tv_sec += 1;
746         pthread_cond_timedwait (&this->free_queue.not_empty, &this->free_queue.mutex, &ts);
747       }
748     }
749   } while (!img);
750 
751   if (img) {
752     *add = img->next;
753     img->next = NULL;
754     this->free_queue.num_buffers--;
755     if (!*add) {
756       this->free_queue.add = add;
757       /* just a safety reset */
758       if (!this->free_queue.first)
759         this->free_queue.num_buffers = 0;
760     }
761   }
762 
763   pthread_mutex_unlock (&this->free_queue.mutex);
764   return img;
765 }
766 
vo_free_get_dupl(vos_t * this,vo_frame_t * s)767 static vo_frame_t *vo_free_get_dupl (vos_t *this, vo_frame_t *s) {
768   vo_frame_t *img, **add;
769 
770   pthread_mutex_lock (&this->free_queue.mutex);
771 
772   add = &this->free_queue.first;
773   while ((img = *add)) {
774     if ((img->format == s->format) && (img->width == s->width)
775       && (img->height == s->height) && (img->ratio == s->ratio))
776       break;
777     add = &img->next;
778   }
779   if (!img) {
780     add = &this->free_queue.first;
781     img = *add;
782   }
783 
784   if (img) {
785     *add = img->next;
786     img->next = NULL;
787     this->free_queue.num_buffers--;
788     if (!*add) {
789       this->free_queue.add = add;
790       /* just a safety reset */
791       if (!this->free_queue.first)
792         this->free_queue.num_buffers = 0;
793     }
794   }
795 
796   pthread_mutex_unlock (&this->free_queue.mutex);
797 
798   return img;
799 }
800 
801 
802 /********************************************************************
803  * frame lock_counter. Basic rule:                                  *
804  * When queuing new frame, we add 2 refs.                           *
805  * 1 for rendering, and 1 for still frame backup and rgb framegrab. *
806  *******************************************************************/
807 
vo_frame_inc2_lock(vo_frame_t * img)808 static void vo_frame_inc2_lock (vo_frame_t *img) {
809   int n;
810 
811   pthread_mutex_lock (&img->mutex);
812 
813   n = (img->lock_counter += 2);
814   if ((n == 3) || (n == 4)) {
815     vos_t *this = (vos_t *)img->port;
816     if (this->frames_extref < this->frames_total)
817       this->frames_extref++;
818   }
819 
820   pthread_mutex_unlock (&img->mutex);
821 }
822 
vo_frame_inc_lock(vo_frame_t * img)823 static void vo_frame_inc_lock (vo_frame_t *img) {
824 
825   pthread_mutex_lock (&img->mutex);
826 
827   img->lock_counter++;
828   if (img->lock_counter == 3) {
829     vos_t *this = (vos_t *)img->port;
830     if (this->frames_extref < this->frames_total)
831       this->frames_extref++;
832   }
833 
834   pthread_mutex_unlock (&img->mutex);
835 }
836 
vo_frame_dec_lock(vo_frame_t * img)837 static void vo_frame_dec_lock (vo_frame_t *img) {
838 
839   pthread_mutex_lock (&img->mutex);
840 
841   img->lock_counter--;
842   if (!img->lock_counter) {
843     vos_t *this = (vos_t *) img->port;
844     vo_free_append (this, img);
845   } else
846   if (img->lock_counter == 2) {
847     vos_t *this = (vos_t *)img->port;
848     if (this->frames_extref > 0)
849       this->frames_extref--;
850   }
851 
852   pthread_mutex_unlock (&img->mutex);
853 }
854 
vo_frame_dec2_lock_int(vos_t * this,vo_frame_t * img)855 static int vo_frame_dec2_lock_int (vos_t *this, vo_frame_t *img) {
856   int n;
857   pthread_mutex_lock (&img->mutex);
858   img->next = NULL;
859   n = img->lock_counter - 2;
860   if (n <= 0) /* "<=" yields better code than "<" there. */
861     n = 0;
862   else if ((n == 1) || (n == 2)) {
863     if (this->frames_extref > 0)
864       this->frames_extref--;
865   }
866   img->lock_counter = n;
867   pthread_mutex_unlock (&img->mutex);
868   return n;
869 }
870 
vo_frame_dec2_lock(vos_t * this,vo_frame_t * img)871 static void vo_frame_dec2_lock (vos_t *this, vo_frame_t *img) {
872   if (!vo_frame_dec2_lock_int (this, img)) {
873     vo_free_append (this, img);
874   }
875 }
876 
877 
878 /********************************************************************
879 * Flush helpers.                                                    *
880 ********************************************************************/
881 
882 /* have this->display_queue.mutex locked!! */
vo_wait_flush(vos_t * this)883 static void vo_wait_flush (vos_t *this) {
884   this->display_queue.num_flush_waiters++;
885   pthread_mutex_lock (&this->trigger_drawing.mutex);
886   this->trigger_drawing.draw = 1;
887   pthread_cond_signal (&this->trigger_drawing.wake);
888   pthread_mutex_unlock (&this->trigger_drawing.mutex);
889   while (this->display_queue.flush_extra || this->display_queue.first)
890     pthread_cond_wait (&this->display_queue.done_flushing, &this->display_queue.mutex);
891   this->display_queue.num_flush_waiters--;
892 }
893 
vo_list_flush(vos_t * this,vo_frame_t * f)894 static void vo_list_flush (vos_t *this, vo_frame_t *f) {
895   vo_frame_t *list = NULL, **add = &list;
896   int n = 0;
897   while (f) {
898     vo_frame_t *next = f->next;
899     if (!vo_frame_dec2_lock_int (this, f)) {
900       *add = f;
901       add = &f->next;
902       n++;
903     }
904     f = next;
905   }
906   vo_free_append_list (this, list, add, n);
907 }
908 
vo_manual_flush(vos_t * this)909 static void vo_manual_flush (vos_t *this) {
910   vo_frame_t *f;
911   pthread_mutex_lock (&this->display_queue.mutex);
912   f = this->display_queue.first;
913   this->display_queue.first = NULL;
914   this->display_queue.add   = &this->display_queue.first;
915   this->display_queue.num_buffers = 0;
916   pthread_mutex_unlock (&this->display_queue.mutex);
917   vo_list_flush (this, f);
918 }
919 
920 
921 /********************************************************************
922  * grabbing RGB images from displayed frames                        *
923  *******************************************************************/
924 
vo_dispose_grab_video_frame(xine_grab_video_frame_t * frame_gen)925 static void vo_dispose_grab_video_frame(xine_grab_video_frame_t *frame_gen)
926 {
927   vos_grab_video_frame_t *frame = (vos_grab_video_frame_t *) frame_gen;
928 
929   if (frame->vo_frame)
930     vo_frame_dec_lock(frame->vo_frame);
931 
932   if (frame->yuv2rgb)
933     frame->yuv2rgb->dispose(frame->yuv2rgb);
934 
935   if (frame->yuv2rgb_factory)
936     frame->yuv2rgb_factory->dispose(frame->yuv2rgb_factory);
937 
938   _x_freep(&frame->img);
939   _x_freep(&frame->grab_frame.img);
940   free(frame);
941 }
942 
943 
vo_grab_grab_video_frame(xine_grab_video_frame_t * frame_gen)944 static int vo_grab_grab_video_frame (xine_grab_video_frame_t *frame_gen) {
945   vos_grab_video_frame_t *frame = (vos_grab_video_frame_t *) frame_gen;
946   vos_t *this = (vos_t *) frame->video_port;
947   vo_frame_t *vo_frame;
948   int format, y_stride, uv_stride;
949   int width, height;
950   uint8_t *base[3];
951 
952   if (frame->grab_frame.flags & XINE_GRAB_VIDEO_FRAME_FLAGS_WAIT_NEXT) {
953     struct timespec ts = {0, 0};
954 
955     /* calculate absolute timeout time */
956     xine_gettime (&ts);
957     ts.tv_sec  +=  frame->grab_frame.timeout / 1000;
958     ts.tv_nsec += (frame->grab_frame.timeout % 1000) * 1000000;
959     if (ts.tv_nsec >= 1000000000) {
960       ts.tv_sec += 1;
961       ts.tv_nsec -= 1000000000;
962     }
963 
964     pthread_mutex_lock(&this->grab.lock);
965 
966     /* insert grab request into grab queue */
967     frame->next = this->grab.request;
968     this->grab.request = frame;
969 
970     /* wait until our request is finished */
971     frame->finished = 0;
972     while (!frame->finished) {
973       if (pthread_cond_timedwait (&this->grab.wake, &this->grab.lock, &ts) == ETIMEDOUT) {
974         vos_grab_video_frame_t *prev = this->grab.request;
975         while (prev) {
976           if (prev == frame) {
977             this->grab.request = frame->next;
978             break;
979           } else if (prev->next == frame) {
980             prev->next = frame->next;
981             break;
982           }
983           prev = prev->next;
984         }
985         frame->next = NULL;
986         pthread_mutex_unlock(&this->grab.lock);
987         return 1;   /* no frame available */
988       }
989     }
990 
991     pthread_mutex_unlock(&this->grab.lock);
992 
993     vo_frame = frame->vo_frame;
994     frame->vo_frame = NULL;
995     if (!vo_frame)
996       return -1; /* error happened */
997   } else {
998     pthread_mutex_lock(&this->grab.lock);
999 
1000     /* use last displayed frame */
1001     vo_frame = this->grab.last_frame;
1002     if (!vo_frame) {
1003       pthread_mutex_unlock(&this->grab.lock);
1004       return 1;   /* no frame available */
1005     }
1006     if (vo_frame->format != XINE_IMGFMT_YV12 && vo_frame->format != XINE_IMGFMT_YUY2 && !vo_frame->proc_provide_standard_frame_data) {
1007       pthread_mutex_unlock(&this->grab.lock);
1008       return -1; /* error happened */
1009     }
1010     vo_frame_inc_lock(vo_frame);
1011     pthread_mutex_unlock(&this->grab.lock);
1012     frame->grab_frame.vpts = vo_frame->vpts;
1013   }
1014 
1015   width = vo_frame->width;
1016   height = vo_frame->height;
1017 
1018   if (vo_frame->format == XINE_IMGFMT_YV12 || vo_frame->format == XINE_IMGFMT_YUY2) {
1019     format = vo_frame->format;
1020     y_stride = vo_frame->pitches[0];
1021     uv_stride = vo_frame->pitches[1];
1022     base[0] = vo_frame->base[0];
1023     base[1] = vo_frame->base[1];
1024     base[2] = vo_frame->base[2];
1025   } else {
1026     /* retrieve standard format image data from output driver */
1027     xine_current_frame_data_t data;
1028     memset(&data, 0, sizeof(data));
1029     vo_frame->proc_provide_standard_frame_data(vo_frame, &data);
1030     if (data.img_size > frame->img_size) {
1031       free(frame->img);
1032       frame->img_size = data.img_size;
1033       frame->img = calloc(data.img_size, sizeof(uint8_t));
1034       if (!frame->img) {
1035         vo_frame_dec_lock(vo_frame);
1036         return -1; /* error happened */
1037       }
1038     }
1039     data.img = frame->img;
1040     vo_frame->proc_provide_standard_frame_data(vo_frame, &data);
1041     format = data.format;
1042     if (format == XINE_IMGFMT_YV12) {
1043       base[0] = data.img;
1044       base[1] = data.img + width * height;
1045       base[2] = data.img + width * height + ((width * height) >> 2);
1046       y_stride  = width;
1047       uv_stride = width >> 1;
1048     } else { // XINE_IMGFMT_YUY2
1049       base[0] = data.img;
1050       base[1] = NULL;
1051       base[2] = NULL;
1052       y_stride  = width * 2;
1053       uv_stride = 0;
1054     }
1055   }
1056 
1057   /* take cropping parameters into account */
1058   {
1059     int crop_left   = (vo_frame->crop_left   + frame->grab_frame.crop_left)  & ~1;
1060     int crop_right  = (vo_frame->crop_right  + frame->grab_frame.crop_right) & ~1;
1061     int crop_top    =  vo_frame->crop_top    + frame->grab_frame.crop_top;
1062     int crop_bottom =  vo_frame->crop_bottom + frame->grab_frame.crop_bottom;
1063 
1064     if (crop_left || crop_right || crop_top || crop_bottom) {
1065       if ((width - crop_left - crop_right) >= 8)
1066         width = width - crop_left - crop_right;
1067       else
1068         crop_left = crop_right = 0;
1069 
1070       if ((height - crop_top - crop_bottom) >= 8)
1071         height = height - crop_top - crop_bottom;
1072       else
1073         crop_top = crop_bottom = 0;
1074 
1075       if (format == XINE_IMGFMT_YV12) {
1076         size_t uv_offs;
1077         base[0] += crop_top * y_stride + crop_left;
1078         uv_offs = (crop_top >> 1) * uv_stride + (crop_left >> 1);
1079         base[1] += uv_offs;
1080         base[2] += uv_offs;
1081       } else { // XINE_IMGFMT_YUY2
1082         base[0] += crop_top * y_stride + crop_left * 2;
1083       }
1084     }
1085   }
1086 
1087   /* get pixel aspect ratio */
1088   {
1089     double sar = 1.0;
1090     {
1091       int sarw = vo_frame->width  - vo_frame->crop_left - vo_frame->crop_right;
1092       int sarh = vo_frame->height - vo_frame->crop_top  - vo_frame->crop_bottom;
1093       if ((vo_frame->ratio > 0.0) && (sarw > 0) && (sarh > 0))
1094         sar = vo_frame->ratio * sarh / sarw;
1095     }
1096 
1097     /* if caller does not specify frame size we return the actual size of grabbed frame */
1098     if ((frame->grab_frame.width <= 0) && (frame->grab_frame.height <= 0)) {
1099       if (sar > 1.0) {
1100         frame->grab_frame.width  = sar * width + 0.5;
1101         frame->grab_frame.height = height;
1102       } else {
1103         frame->grab_frame.width  = width;
1104         frame->grab_frame.height = (double)height / sar + 0.5;
1105       }
1106     } else if (frame->grab_frame.width <= 0)
1107       frame->grab_frame.width = frame->grab_frame.height * width * sar / height + 0.5;
1108     else if (frame->grab_frame.height <= 0)
1109       frame->grab_frame.height = (frame->grab_frame.width * height) / (sar * width) + 0.5;
1110   }
1111 
1112   /* allocate grab frame image buffer */
1113   if (frame->grab_frame.width != frame->grab_width || frame->grab_frame.height != frame->grab_height) {
1114     _x_freep(&frame->grab_frame.img);
1115   }
1116   if (frame->grab_frame.img == NULL) {
1117     frame->grab_frame.img = (uint8_t *) calloc(frame->grab_frame.width * frame->grab_frame.height, 3);
1118     if (frame->grab_frame.img == NULL) {
1119       vo_frame_dec_lock(vo_frame);
1120       return -1; /* error happened */
1121     }
1122   }
1123 
1124   /* initialize yuv2rgb factory */
1125   if (!frame->yuv2rgb_factory) {
1126     int cm = VO_GET_FLAGS_CM (vo_frame->flags);
1127     frame->yuv2rgb_factory = yuv2rgb_factory_init(MODE_24_RGB, 0, NULL);
1128     if (!frame->yuv2rgb_factory) {
1129       vo_frame_dec_lock(vo_frame);
1130       return -1; /* error happened */
1131     }
1132     if ((cm >> 1) == 2) /* color matrix undefined */
1133       cm = (cm & 1) |
1134         ((vo_frame->height - vo_frame->crop_top - vo_frame->crop_bottom >= 720) ||
1135          (vo_frame->width - vo_frame->crop_left - vo_frame->crop_right >= 1280) ? 2 : 10);
1136     else if ((cm >> 1) == 0) /* converted RGB source, always ITU 601 */
1137       cm = (cm & 1) | 10;
1138     frame->yuv2rgb_factory->set_csc_levels (frame->yuv2rgb_factory, 0, 128, 128, cm);
1139   }
1140 
1141   /* retrieve a yuv2rgb converter */
1142   if (!frame->yuv2rgb) {
1143     frame->yuv2rgb = frame->yuv2rgb_factory->create_converter(frame->yuv2rgb_factory);
1144     if (!frame->yuv2rgb) {
1145       vo_frame_dec_lock(vo_frame);
1146       return -1; /* error happened */
1147     }
1148   }
1149 
1150   /* configure yuv2rgb converter */
1151   if (width != frame->vo_width ||
1152         height != frame->vo_height ||
1153         frame->grab_frame.width != frame->grab_width ||
1154         frame->grab_frame.height != frame->grab_height ||
1155         y_stride != frame->y_stride ||
1156         uv_stride != frame->uv_stride) {
1157     frame->vo_width = width;
1158     frame->vo_height = height;
1159     frame->grab_width = frame->grab_frame.width;
1160     frame->grab_height = frame->grab_frame.height;
1161     frame->y_stride = y_stride;
1162     frame->uv_stride = uv_stride;
1163     frame->yuv2rgb->configure(frame->yuv2rgb, width, height, y_stride, uv_stride, frame->grab_width, frame->grab_height, frame->grab_width * 3);
1164   }
1165 
1166   /* convert YUV to RGB image taking possible scaling into account */
1167   if(format == XINE_IMGFMT_YV12)
1168     frame->yuv2rgb->yuv2rgb_fun(frame->yuv2rgb, frame->grab_frame.img, base[0], base[1], base[2]);
1169   else
1170     frame->yuv2rgb->yuy22rgb_fun(frame->yuv2rgb, frame->grab_frame.img, base[0]);
1171 
1172   vo_frame_dec_lock(vo_frame);
1173   return 0;
1174 }
1175 
1176 
vo_new_grab_video_frame(xine_video_port_t * this_gen)1177 static xine_grab_video_frame_t *vo_new_grab_video_frame(xine_video_port_t *this_gen)
1178 {
1179   vos_grab_video_frame_t *frame = calloc(1, sizeof(vos_grab_video_frame_t));
1180   if (frame) {
1181     frame->grab_frame.dispose = vo_dispose_grab_video_frame;
1182     frame->grab_frame.grab = vo_grab_grab_video_frame;
1183     frame->grab_frame.vpts = -1;
1184     frame->grab_frame.timeout = XINE_GRAB_VIDEO_FRAME_DEFAULT_TIMEOUT;
1185     frame->video_port = this_gen;
1186   }
1187   return (xine_grab_video_frame_t *)frame;
1188 }
1189 
1190 
1191 /* Use this after rendering a live frame (not for still frame duplicates). */
vo_grab_current_frame(vos_t * this,vo_frame_t * vo_frame,int64_t vpts)1192 static void vo_grab_current_frame (vos_t *this, vo_frame_t *vo_frame, int64_t vpts)
1193 {
1194   pthread_mutex_lock(&this->grab.lock);
1195 
1196   /* hold current frame for still frame generation and snapshot feature */
1197   if (this->grab.last_frame)
1198     vo_frame_dec_lock(this->grab.last_frame);
1199   this->grab.last_frame = vo_frame;
1200 
1201   /* process grab queue */
1202   vos_grab_video_frame_t *frame = this->grab.request;
1203   if (frame) {
1204     do {
1205       vos_grab_video_frame_t *next;
1206       if (frame->vo_frame)
1207         vo_frame_dec_lock(frame->vo_frame);
1208       frame->vo_frame = NULL;
1209 
1210       if (vo_frame->format == XINE_IMGFMT_YV12 || vo_frame->format == XINE_IMGFMT_YUY2 || vo_frame->proc_provide_standard_frame_data) {
1211         vo_frame_inc_lock(vo_frame);
1212         frame->vo_frame = vo_frame;
1213         frame->grab_frame.vpts = vpts;
1214       }
1215 
1216       frame->finished = 1;
1217       next = frame->next;
1218       frame->next = NULL;
1219       frame = next;
1220     } while (frame);
1221 
1222     this->grab.request = NULL;
1223     pthread_cond_broadcast(&this->grab.wake);
1224   }
1225 
1226   pthread_mutex_unlock(&this->grab.lock);
1227 }
1228 
1229 
1230 /* call vo_driver->proc methods for the entire frame */
vo_frame_driver_proc(vo_frame_t * img)1231 static void vo_frame_driver_proc(vo_frame_t *img)
1232 {
1233   if (img->proc_frame) {
1234     img->proc_frame(img);
1235   }
1236   if (img->proc_called) return;
1237 
1238   if (img->proc_slice) {
1239     int height = img->height;
1240     uint8_t* src[3];
1241 
1242     switch (img->format) {
1243     case XINE_IMGFMT_YV12:
1244       src[0] = img->base[0];
1245       src[1] = img->base[1];
1246       src[2] = img->base[2];
1247       while ((height -= 16) > -16) {
1248         img->proc_slice(img, src);
1249         src[0] += 16 * img->pitches[0];
1250         src[1] +=  8 * img->pitches[1];
1251         src[2] +=  8 * img->pitches[2];
1252       }
1253       break;
1254     case XINE_IMGFMT_YUY2:
1255       src[0] = img->base[0];
1256       while ((height -= 16) > -16) {
1257         img->proc_slice(img, src);
1258         src[0] += 16 * img->pitches[0];
1259       }
1260       break;
1261     }
1262   }
1263 }
1264 
1265 
1266 /********************************************************************
1267  * called by video decoder:                                         *
1268  * get_frame  => alloc frame for rendering                          *
1269  * frame_draw => queue finished frame for display                   *
1270  * frame_free => frame no longer used as reference frame by decoder *
1271  *******************************************************************/
1272 
vo_get_frame(xine_video_port_t * this_gen,uint32_t width,uint32_t height,double ratio,int format,int flags)1273 static vo_frame_t *vo_get_frame (xine_video_port_t *this_gen,
1274 				 uint32_t width, uint32_t height,
1275 				 double ratio, int format,
1276 				 int flags) {
1277 
1278   vo_frame_t *img;
1279   vos_t      *this = (vos_t *) this_gen;
1280 
1281   lprintf ("get_frame (%d x %d)\n", width, height);
1282 
1283   while (1) {
1284 
1285     img = vo_free_queue_get (this, width, height, ratio, format, flags);
1286 
1287     lprintf ("got a frame -> pthread_mutex_lock (&img->mutex)\n");
1288 
1289     /* some decoders report strange ratios */
1290     if (ratio <= 0.0)
1291       ratio = (double)width / (double)height;
1292 
1293     pthread_mutex_lock (&img->mutex);
1294     img->lock_counter   = 1;
1295     img->width          = width;
1296     img->height         = height;
1297     img->ratio          = ratio;
1298     img->format         = format;
1299     img->flags          = flags;
1300     img->proc_called    = 0;
1301     img->bad_frame      = 0;
1302     img->progressive_frame  = 0;
1303     img->repeat_first_field = 0;
1304     img->top_field_first    = 1;
1305     img->crop_left      = 0;
1306     img->crop_right     = 0;
1307     img->crop_top       = 0;
1308     img->crop_bottom    = 0;
1309     img->overlay_offset_x = 0;
1310     img->overlay_offset_y = 0;
1311     img->stream         = NULL;
1312 
1313     _x_extra_info_reset ( img->extra_info );
1314 
1315     /* let driver ensure this image has the right format */
1316 
1317     this->driver->update_frame_format (this->driver, img, width, height,
1318                                        ratio, format, flags);
1319 
1320     pthread_mutex_unlock (&img->mutex);
1321 
1322     if (!width || img->width)
1323       break;
1324 
1325     xprintf (&this->xine->x, XINE_VERBOSITY_LOG,
1326       _("video_out: found an unusable frame (%dx%d, format %0x08x) - no memory??\n"),
1327       width, height, img->format);
1328     img->lock_counter = 0;
1329     vo_free_append (this, img);
1330 
1331     /* check if we're allowed to return NULL */
1332     if (flags & VO_GET_FRAME_MAY_FAIL)
1333       return NULL;
1334   }
1335 
1336   /* update frame usage stats. No need to lock queues for that I guess :-) */
1337   {
1338     int frames_used;
1339     frames_used = this->frames_total;
1340     frames_used -= this->free_queue.num_buffers;
1341     frames_used -= this->display_queue.num_buffers;
1342     frames_used -= this->rp.ready_num;
1343     frames_used += this->frames_extref;
1344     if (frames_used > this->frames_peak_used)
1345       this->frames_peak_used = frames_used;
1346   }
1347 
1348   lprintf ("get_frame (%d x %d) done\n", width, height);
1349 
1350   return img;
1351 }
1352 
1353 /* crop_frame() will allocate a new frame to copy in the given image
1354  * while cropping. maybe someday this will be an automatic post plugin.
1355  */
crop_frame(xine_video_port_t * this_gen,vo_frame_t * img)1356 static vo_frame_t * crop_frame( xine_video_port_t *this_gen, vo_frame_t *img ) {
1357 
1358   vo_frame_t *dupl;
1359 
1360   dupl = vo_get_frame ( this_gen,
1361                         img->width - img->crop_left - img->crop_right,
1362                         img->height - img->crop_top - img->crop_bottom,
1363                         img->ratio, img->format, img->flags | VO_BOTH_FIELDS);
1364 
1365   dupl->progressive_frame  = img->progressive_frame;
1366   dupl->repeat_first_field = img->repeat_first_field;
1367   dupl->top_field_first    = img->top_field_first;
1368   dupl->overlay_offset_x   = img->overlay_offset_x;
1369   dupl->overlay_offset_y   = img->overlay_offset_y;
1370 
1371   switch (img->format) {
1372   case XINE_IMGFMT_YV12:
1373     yv12_to_yv12(
1374      /* Y */
1375       img->base[0] + img->crop_top * img->pitches[0] +
1376         img->crop_left, img->pitches[0],
1377       dupl->base[0], dupl->pitches[0],
1378      /* U */
1379       img->base[1] + img->crop_top/2 * img->pitches[1] +
1380         img->crop_left/2, img->pitches[1],
1381       dupl->base[1], dupl->pitches[1],
1382      /* V */
1383       img->base[2] + img->crop_top/2 * img->pitches[2] +
1384         img->crop_left/2, img->pitches[2],
1385       dupl->base[2], dupl->pitches[2],
1386      /* width x height */
1387       dupl->width, dupl->height);
1388     break;
1389   case XINE_IMGFMT_YUY2:
1390     yuy2_to_yuy2(
1391      /* src */
1392       img->base[0] + img->crop_top * img->pitches[0] +
1393         img->crop_left*2, img->pitches[0],
1394      /* dst */
1395       dupl->base[0], dupl->pitches[0],
1396      /* width x height */
1397       dupl->width, dupl->height);
1398     break;
1399   }
1400 
1401   dupl->bad_frame   = 0;
1402   dupl->pts         = img->pts;
1403   dupl->vpts        = img->vpts;
1404   dupl->proc_called = 0;
1405 
1406   dupl->duration  = img->duration;
1407   dupl->is_first  = img->is_first;
1408 
1409   dupl->stream    = img->stream;
1410 
1411   memcpy( dupl->extra_info, img->extra_info, sizeof(extra_info_t) );
1412 
1413   /* delay frame processing for now, we might not even need it (eg. frame will be discarded) */
1414   /* vo_frame_driver_proc(dupl); */
1415 
1416   return dupl;
1417 }
1418 
vo_frame_draw(vo_frame_t * img,xine_stream_t * s)1419 static int vo_frame_draw (vo_frame_t *img, xine_stream_t *s) {
1420 
1421   xine_stream_private_t *stream = (xine_stream_private_t *)s;
1422   vos_t         *this = (vos_t *) img->port;
1423   int            frames_to_skip, first_frame_flag = 0;
1424 
1425   img->stream = NULL;
1426 
1427   if (this->display_queue.discard_frames) {
1428     /* Now that we have the auto gapless switch it should be safe to always drop here. */
1429     lprintf ("i'm in flush mode, not appending this frame to queue\n");
1430     return 0;
1431   }
1432 
1433   /* handle anonymous streams like NULL for easy checking */
1434   if (&stream->s == XINE_ANON_STREAM) stream = NULL;
1435 
1436   if (stream) {
1437     /* Grabbing display_queue.mutex / first_frame_lock when testing
1438      * discard_frames / first_frame_flag is safe but slow. Most of the time these flags
1439      * will be 0. Lets try without lock first, and look closer after a flush only. */
1440     first_frame_flag = stream->side_streams[0]->first_frame.flag;
1441     if (this->display_queue.flushed) {
1442       pthread_mutex_lock (&this->display_queue.mutex);
1443       if (this->display_queue.flushed) {
1444         this->display_queue.flushed = 0;
1445         pthread_mutex_unlock (&this->display_queue.mutex);
1446         pthread_mutex_lock (&stream->side_streams[0]->first_frame.lock);
1447         first_frame_flag = stream->side_streams[0]->first_frame.flag;
1448         pthread_mutex_unlock (&stream->side_streams[0]->first_frame.lock);
1449       } else {
1450         pthread_mutex_unlock (&this->display_queue.mutex);
1451       }
1452     }
1453     if (first_frame_flag >= 2) {
1454       /* Frame reordering and/or multithreaded deoders feature an initial delay.
1455        * Even worse: mpeg-ts does not seek to keyframes, as that would need quite some
1456        * decoder knowledge. As a result, there often burst in many "bad" frames here quickly.
1457        * Dont let these mess up timing, generate high frames_to_skip values,
1458        * and kill the following keyframe seq with that.
1459        */
1460       this->last_delivery_pts = 0;
1461       if (img->bad_frame) {
1462         this->num_frames_burst++;
1463         return 0;
1464       }
1465       if (this->num_frames_burst) {
1466         xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
1467           "video_out: dropped %d bad frames after seek.\n", this->num_frames_burst);
1468         this->num_frames_burst = 0;
1469       }
1470     }
1471     img->stream = &stream->s;
1472     _x_extra_info_merge( img->extra_info, stream->video_decoder_extra_info );
1473     stream->s.metronom->got_video_frame (stream->s.metronom, img);
1474 #ifdef ADD_KEYFRAME_INDEX
1475     if (FIXME: IS_KEYFRAME (img)) {
1476       if (this->keyframe_mode == 0) {
1477         if (!stream->index_array && stream->input_plugin && INPUT_IS_SEEKABLE (stream->input_plugin)) {
1478           xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
1479             "video_out: no keyframe index found, lets do it from this side.\n");
1480           this->keyframe_mode = 1;
1481         } else {
1482           this->keyframe_mode = -1;
1483         }
1484       }
1485       if (this->keyframe_mode > 0) {
1486         xine_keyframes_entry_t entry;
1487         entry.msecs = img->extra_info->input_time;
1488         entry.normpos = img->extra_info->input_normpos;
1489         _x_keyframes_add (stream, &entry);
1490       }
1491     }
1492 #endif
1493   }
1494   this->current_width = img->width;
1495   this->current_height = img->height;
1496   this->current_duration = img->duration;
1497 
1498   if (!this->grab_only) {
1499 
1500     img->extra_info->vpts = img->vpts;
1501 
1502     this->last_delivery_pts = this->clock->get_current_time (this->clock);
1503 
1504     lprintf ("got image at master vpts %" PRId64 ". vpts for picture is %" PRId64 " (pts was %" PRId64 ")\n",
1505       this->last_delivery_pts, img->vpts, img->pts);
1506 
1507     this->num_frames_delivered++;
1508 
1509     /* Frame dropping slow start:
1510      *   The engine starts to drop frames if there are less than frame_drop_limit
1511      *   frames in advance. There might be a problem just after a seek because
1512      *   there is no frame in advance yet.
1513      *   The following code increases progressively the frame_drop_limit (-2 -> 3)
1514      *   after a seek to give a chance to the engine to display the first frames
1515      *   smoothly before starting to drop frames if the decoder is really too
1516      *   slow.
1517      *   The above numbers are the result of frame_drop_limit_max beeing 3. They
1518      *   will be (-4 -> 1) when frame_drop_limit_max is only 1. This maximum value
1519      *   depends on the number of video buffers which the output device provides.
1520      */
1521     if (first_frame_flag >= 2)
1522       this->frame_drop_cpt = 10;
1523 
1524     if (this->frame_drop_cpt) {
1525       this->frame_drop_limit = this->frame_drop_limit_max - (this->frame_drop_cpt >> 1);
1526       this->frame_drop_cpt--;
1527     }
1528 
1529     /* do not skip decoding until output fifo frames are consumed */
1530     if (this->display_queue.num_buffers + this->rp.ready_num < this->frame_drop_limit) {
1531       int duration = img->duration > 0 ? img->duration : DEFAULT_FRAME_DURATION;
1532       frames_to_skip = (this->last_delivery_pts - img->vpts) / duration;
1533       frames_to_skip = (frames_to_skip + this->frame_drop_limit) * 2;
1534       if (frames_to_skip < 0)
1535         frames_to_skip = 0;
1536     } else {
1537       frames_to_skip = 0;
1538     }
1539 
1540     /* Do not drop frames immediately, but remember this as suggestion and give
1541      * decoder a further chance to supply frames.
1542      * This avoids unnecessary frame drops in situations where there is only
1543      * a very little number of image buffers, e. g. when using xxmc.
1544      */
1545     if (!frames_to_skip) {
1546       this->frame_drop_suggested = 0;
1547     } else {
1548       if (!this->frame_drop_suggested) {
1549         this->frame_drop_suggested = 1;
1550         frames_to_skip = 0;
1551       }
1552     }
1553 
1554     lprintf ("delivery diff : %" PRId64 ", current vpts is %" PRId64 ", %d frames to skip\n",
1555       img->vpts - this->last_delivery_pts, this->last_delivery_pts, frames_to_skip);
1556 
1557   } else {
1558     frames_to_skip = 0;
1559   }
1560 
1561 
1562   if (!img->bad_frame) {
1563 
1564     int img_already_locked = 0;
1565 
1566     /* add cropping requested by frontend */
1567     img->crop_left   = (img->crop_left + this->crop_left) & ~1;
1568     img->crop_right  = (img->crop_right + this->crop_right) & ~1;
1569     img->crop_top    += this->crop_top;
1570     img->crop_bottom += this->crop_bottom;
1571 
1572     /* perform cropping when vo driver does not support it */
1573     if( (img->crop_left || img->crop_top ||
1574          img->crop_right || img->crop_bottom) &&
1575         (this->grab_only ||
1576          !(this->driver->get_capabilities (this->driver) & VO_CAP_CROP)) ) {
1577       if (img->format == XINE_IMGFMT_YV12 || img->format == XINE_IMGFMT_YUY2) {
1578         img->overlay_offset_x -= img->crop_left;
1579         img->overlay_offset_y -= img->crop_top;
1580         img = crop_frame( img->port, img );
1581         img->lock_counter = 2;
1582         img_already_locked = 1;
1583       } else {
1584 	/* noone knows how to crop this, so we can only ignore the cropping */
1585 	img->crop_left   = 0;
1586 	img->crop_top    = 0;
1587 	img->crop_right  = 0;
1588 	img->crop_bottom = 0;
1589       }
1590     }
1591 
1592     /* do not call proc_*() for frames that will be dropped */
1593     if( !frames_to_skip && !img->proc_called )
1594       vo_frame_driver_proc(img);
1595 
1596     /*
1597      * put frame into FIFO-Buffer
1598      */
1599 
1600     lprintf ("frame is ok => appending to display buffer\n");
1601 
1602     /*
1603      * check for first frame after seek and mark it
1604      */
1605     img->is_first = 0;
1606     if (first_frame_flag >= 2) {
1607       /* We can always do the frame's native stream here. We know its there. */
1608       xine_stream_private_t *m = stream->side_streams[0];
1609       pthread_mutex_lock (&m->first_frame.lock);
1610       if (m->first_frame.flag >= 2) {
1611         if ((m->first_frame.flag > 2) || this->grab_only) {
1612           m->first_frame.flag = 0;
1613           pthread_cond_broadcast (&m->first_frame.reached);
1614         } else {
1615           m->first_frame.flag = 1;
1616         }
1617         img->is_first = FIRST_FRAME_MAX_POLL;
1618         lprintf ("get_next_video_frame first_frame_reached\n");
1619       }
1620       pthread_mutex_unlock (&m->first_frame.lock);
1621     }
1622     /* avoid a complex deadlock situation caused by net_buf_control */
1623     if (!xine_rwlock_tryrdlock (&this->streams_lock)) {
1624       xine_stream_private_t **s;
1625       for (s = this->streams; *s; s++) {
1626         xine_stream_private_t *m;
1627         if (*s == stream)
1628           continue;
1629         m = (*s)->side_streams[0];
1630         /* a little speedup */
1631         if (m->first_frame.flag < 2)
1632           continue;
1633         pthread_mutex_lock (&m->first_frame.lock);
1634         if (m->first_frame.flag >= 2) {
1635           if ((m->first_frame.flag > 2) || this->grab_only) {
1636             m->first_frame.flag = 0;
1637             pthread_cond_broadcast (&m->first_frame.reached);
1638           } else {
1639             m->first_frame.flag = 1;
1640           }
1641           img->is_first = FIRST_FRAME_MAX_POLL;
1642           lprintf ("get_next_video_frame first_frame_reached\n");
1643         }
1644         pthread_mutex_unlock (&m->first_frame.lock);
1645       }
1646       xine_rwlock_unlock (&this->streams_lock);
1647     }
1648 
1649     if (!img_already_locked)
1650       vo_frame_inc2_lock (img);
1651     vo_display_reref_append (this, img);
1652 
1653     if (img->is_first && (this->display_queue.first == img)) {
1654       /* wake up render thread */
1655       pthread_mutex_lock (&this->trigger_drawing.mutex);
1656       this->trigger_drawing.draw = 1;
1657       pthread_cond_signal (&this->trigger_drawing.wake);
1658       pthread_mutex_unlock (&this->trigger_drawing.mutex);
1659     }
1660 
1661   } else {
1662     lprintf ("bad_frame\n");
1663 
1664     if (stream) {
1665       xine_stream_private_t *m = stream->side_streams[0];
1666       xine_current_extra_info_set (m, img->extra_info);
1667     }
1668 
1669     this->num_frames_skipped++;
1670   }
1671 
1672   /*
1673    * performance measurement
1674    */
1675 
1676   if (this->num_frames_delivered == 200) {
1677     int send_event;
1678     xine_stream_private_t **it;
1679 
1680     /* 100 * n / num_frames_delivered */
1681     if (((this->num_frames_skipped >> 1)   > this->warn_skipped_threshold) ||
1682         ((this->num_frames_discarded >> 1) > this->warn_discarded_threshold))
1683       this->warn_threshold_exceeded++;
1684     else
1685       this->warn_threshold_exceeded = 0;
1686 
1687     /* make sure threshold has being consistently exceeded - 5 times in a row
1688      * (that is, this is not just a small burst of dropped frames).
1689      */
1690     send_event = (this->warn_threshold_exceeded == 5 &&
1691                   !this->warn_threshold_event_sent);
1692     this->warn_threshold_event_sent = send_event;
1693 
1694     xine_rwlock_rdlock (&this->streams_lock);
1695     for (it = this->streams; *it; it++) {
1696       int skipped, discarded;
1697       stream = *it;
1698 
1699       /* 1000 * n / num_frames_delivered */
1700       skipped   = 5 * this->num_frames_skipped;
1701       discarded = 5 * this->num_frames_discarded;
1702       _x_stream_info_set (&stream->s, XINE_STREAM_INFO_SKIPPED_FRAMES, skipped);
1703       _x_stream_info_set (&stream->s, XINE_STREAM_INFO_DISCARDED_FRAMES, discarded);
1704 
1705       /* we send XINE_EVENT_DROPPED_FRAMES to frontend to warn that
1706        * number of skipped or discarded frames is too high.
1707        */
1708       if( send_event ) {
1709          xine_event_t          event;
1710          xine_dropped_frames_t data;
1711 
1712          event.type        = XINE_EVENT_DROPPED_FRAMES;
1713          event.stream      = &stream->s;
1714          event.data        = &data;
1715          event.data_length = sizeof(data);
1716          data.skipped_frames = skipped;
1717          data.skipped_threshold = this->warn_skipped_threshold * 10;
1718          data.discarded_frames = discarded;
1719          data.discarded_threshold = this->warn_discarded_threshold * 10;
1720          xine_event_send (&stream->s, &event);
1721       }
1722     }
1723     xine_rwlock_unlock (&this->streams_lock);
1724 
1725 
1726     if( this->num_frames_skipped || this->num_frames_discarded ) {
1727       xine_log(&this->xine->x, XINE_LOG_MSG,
1728 	       _("%d frames delivered, %d frames skipped, %d frames discarded\n"),
1729                200,
1730 	       this->num_frames_skipped, this->num_frames_discarded);
1731     }
1732 
1733     this->num_frames_delivered = 0;
1734     this->num_frames_discarded = 0;
1735     this->num_frames_skipped   = 0;
1736   }
1737 
1738   return frames_to_skip;
1739 }
1740 
1741 
1742 /********************************************************************
1743  * video out loop aka render thread related                         *
1744  *******************************************************************/
1745 
1746 #define ADD_READY_FRAMES \
1747   if (this->rp.ready_num < 2) { \
1748     if (!this->rp.ready_num || this->display_queue.first) \
1749       vo_ready_refill (this); \
1750   }
1751 
vo_ready_refill(vos_t * this)1752 static void vo_ready_refill (vos_t *this) {
1753   vo_frame_t *first, **add;
1754 
1755   pthread_mutex_lock (&this->display_queue.mutex);
1756   first = this->display_queue.first;
1757   if (!first) {
1758     this->display_queue.flush_extra = this->rp.ready_num;
1759     pthread_mutex_unlock (&this->display_queue.mutex);
1760     return;
1761   }
1762   add = this->display_queue.add;
1763   this->rp.ready_num  += this->display_queue.num_buffers;
1764   this->display_queue.flush_extra = this->rp.ready_num;
1765   this->display_queue.first = NULL;
1766   this->display_queue.add = &this->display_queue.first;
1767   this->display_queue.num_buffers = 0;
1768   pthread_mutex_unlock (&this->display_queue.mutex);
1769 
1770   *(this->rp.ready_add) = first;
1771   this->rp.ready_add    = add;
1772 }
1773 
vo_ready_get_all(vos_t * this)1774 static vo_frame_t *vo_ready_get_all (vos_t *this) {
1775   vo_frame_t *first;
1776 
1777   pthread_mutex_lock (&this->display_queue.mutex);
1778   first = this->display_queue.first;
1779   if (first) {
1780     this->display_queue.first = NULL;
1781     this->display_queue.add   = &this->display_queue.first;
1782     this->display_queue.num_buffers = 0;
1783   }
1784   this->display_queue.flush_extra = 0;
1785   this->rp.need_flush_signal = this->display_queue.num_flush_waiters;
1786   pthread_mutex_unlock (&this->display_queue.mutex);
1787 
1788   *(this->rp.ready_add) = first;
1789   first = this->rp.ready_first;
1790   this->rp.ready_first = NULL;
1791   this->rp.ready_add   = &this->rp.ready_first;
1792   this->rp.ready_num   = 0;
1793   return first;
1794 }
1795 
vo_ready_pop(vos_t * this)1796 static vo_frame_t *vo_ready_pop (vos_t *this) {
1797   vo_frame_t *img;
1798 
1799   img = this->rp.ready_first;
1800   this->rp.ready_first = img->next;
1801   img->next = NULL;
1802   if (!this->rp.ready_first) {
1803     this->rp.ready_add = &this->rp.ready_first;
1804     this->rp.ready_num = 0;
1805   } else {
1806     this->rp.ready_num--;
1807   }
1808 
1809   return img;
1810 }
1811 
vo_ready_get_dupl(vos_t * this,vo_frame_t * s)1812 static vo_frame_t *vo_ready_get_dupl (vos_t *this, vo_frame_t *s) {
1813   vo_frame_t *img, **add, **fadd = NULL;
1814 
1815   add = &this->rp.ready_first;
1816   while ((img = *add)) {
1817     if ((img->lock_counter <= 2) && (img != s)) {
1818       if ((img->format == s->format) && (img->width == s->width)
1819         && (img->height == s->height) && (img->ratio == s->ratio))
1820         break;
1821       if (!fadd)
1822         fadd = add;
1823     }
1824     add = &img->next;
1825   }
1826   if (!img) {
1827     if (!fadd)
1828       return NULL;
1829     add = fadd;
1830     img = *add;
1831   }
1832 
1833   *add = img->next;
1834   img->next = NULL;
1835   this->rp.ready_num--;
1836   if (!*add) {
1837     this->rp.ready_add = add;
1838     /* just a safety reset */
1839     if (!this->rp.ready_first)
1840       this->rp.ready_num = 0;
1841   }
1842 
1843   return img;
1844 }
1845 
1846 /* duplicate_frame(): this function is used to keep playing frames
1847  * while video is still or player paused.
1848  *
1849  * frame allocation inside vo loop is dangerous:
1850  * we must never wait for a free frame -> deadlock condition.
1851  * to avoid deadlocks we don't use vo_free_queue_get ()
1852  * but vo_*_get_dupl () instead.
1853  */
duplicate_frame(vos_t * this,vo_frame_t * img)1854 static vo_frame_t *duplicate_frame (vos_t *this, vo_frame_t *img) {
1855   vo_frame_t *dupl;
1856 
1857   if (!img)
1858     return NULL;
1859 
1860   dupl = vo_free_get_dupl (this, img);
1861   if (!dupl) {
1862     /* OK we run out of free frames. Try to whistle back a frame already waiting for display.
1863        Search for one that is _not_ a DR1 reference frame that the decoder wants unchanged */
1864     vo_ready_refill (this);
1865     dupl = vo_ready_get_dupl (this, img);
1866     if (!dupl)
1867       return NULL;
1868   }
1869 
1870   pthread_mutex_lock (&dupl->mutex);
1871   dupl->lock_counter   = 1;
1872   dupl->width          = img->width;
1873   dupl->height         = img->height;
1874   dupl->ratio          = img->ratio;
1875   dupl->format         = img->format;
1876   dupl->flags          = img->flags | VO_BOTH_FIELDS;
1877   dupl->progressive_frame  = img->progressive_frame;
1878   dupl->repeat_first_field = img->repeat_first_field;
1879   dupl->top_field_first    = img->top_field_first;
1880   dupl->crop_left      = img->crop_left;
1881   dupl->crop_right     = img->crop_right;
1882   dupl->crop_top       = img->crop_top;
1883   dupl->crop_bottom    = img->crop_bottom;
1884   dupl->overlay_offset_x = img->overlay_offset_x;
1885   dupl->overlay_offset_y = img->overlay_offset_y;
1886 
1887   dupl->stream = img->stream;
1888 
1889   this->driver->update_frame_format (this->driver, dupl, dupl->width, dupl->height,
1890 				     dupl->ratio, dupl->format, dupl->flags);
1891 
1892   pthread_mutex_unlock (&dupl->mutex);
1893 
1894   if (img->width && !dupl->width) {
1895     /* driver failed to set up render space */
1896     xprintf (&this->xine->x, XINE_VERBOSITY_LOG,
1897       _("video_out: found an unusable frame (%dx%d, format %0x08x) - no memory??\n"),
1898       img->width, img->height, img->format);
1899     dupl->lock_counter = 0;
1900     vo_free_append (this, dupl);
1901     return NULL;
1902   }
1903 
1904   if (dupl->proc_duplicate_frame_data) {
1905     dupl->proc_duplicate_frame_data(dupl,img);
1906   } else {
1907 
1908     switch (img->format) {
1909     case XINE_IMGFMT_YV12:
1910       yv12_to_yv12(
1911        /* Y */
1912         img->base[0], img->pitches[0],
1913         dupl->base[0], dupl->pitches[0],
1914        /* U */
1915         img->base[1], img->pitches[1],
1916         dupl->base[1], dupl->pitches[1],
1917        /* V */
1918         img->base[2], img->pitches[2],
1919         dupl->base[2], dupl->pitches[2],
1920        /* width x height */
1921         img->width, img->height);
1922       break;
1923     case XINE_IMGFMT_YUY2:
1924       yuy2_to_yuy2(
1925        /* src */
1926         img->base[0], img->pitches[0],
1927        /* dst */
1928         dupl->base[0], dupl->pitches[0],
1929        /* width x height */
1930         img->width, img->height);
1931       break;
1932     }
1933   }
1934 
1935   dupl->bad_frame   = 0;
1936   dupl->pts         = 0;
1937   dupl->vpts        = 0;
1938   dupl->proc_called = 0;
1939 
1940   dupl->duration  = img->duration;
1941   dupl->is_first  = 0;
1942 
1943   /* extra info is thrown away, because it is not up to date */
1944   _x_extra_info_reset (dupl->extra_info);
1945   dupl->future_frame = NULL;
1946 
1947   /* delay frame processing for now, we might not even need it (eg. frame will be discarded) */
1948   /* vo_frame_driver_proc(dupl); */
1949 
1950   return dupl;
1951 }
1952 
check_redraw_needed(vos_t * this,int64_t vpts)1953 static void check_redraw_needed (vos_t *this, int64_t vpts) {
1954 
1955   if (this->overlay_source) {
1956     if( this->overlay_source->redraw_needed (this->overlay_source, vpts) )
1957       this->redraw_needed = 1;
1958   }
1959 
1960   /* calling the frontend's frame output hook (via driver->redraw_needed () here)
1961    * while flushing (xine_stop ()) may freeze.
1962    */
1963   if (!(this->display_queue.discard_frames && (this->rp.ready_first || this->display_queue.first))) {
1964     if (this->driver->redraw_needed (this->driver))
1965       this->redraw_needed = 1;
1966   }
1967 
1968   if (this->redraw_needed) {
1969     this->rp.poll_time  = 40000; /* 25 fps */
1970     this->rp.poll_limit = 42000; /* < 24 fps */
1971     this->rp.poll_num   = 200;
1972   } else {
1973     if (this->rp.poll_num > 0) {
1974       if (--this->rp.poll_num == 0) {
1975         this->rp.poll_time  = 200000; /* 5 fps */
1976         this->rp.poll_limit = 200000; /* 5 fps */
1977       }
1978     }
1979   }
1980 }
1981 
next_frame(vos_t * this,int64_t * vpts)1982 static vo_frame_t *next_frame (vos_t *this, int64_t *vpts) {
1983 
1984   vo_frame_t   *img;
1985 
1986   /* when flushing, drop everything now, and return latest "first" frame if any.
1987    * FIXME: when switching from movie to logo, somebody briefly flashes VO_PROP_DISCARD_FRAMES.
1988    * This kills up to num_frames from the end. For now, just forget the flush there.
1989    * That happens here automagically because we come here late ;-)
1990    * FIXED: by auto gapless switch.
1991    */
1992   if (this->display_queue.discard_frames) {
1993     vo_frame_t *keep[2], *freelist = NULL, **add = &freelist;
1994     int n = 0, a = 0;
1995     keep[0] = NULL;
1996     keep[1] = this->rp.last_flushed;
1997     /* Take out all at once, but keep decoder blocked for now. */
1998     img = vo_ready_get_all (this);
1999     /* Scan for stuff we want to keep. */
2000     while (img) {
2001       vo_frame_t *f = keep[(img->is_first <= 0)];
2002       n++;
2003       if (f) {
2004         if (!vo_frame_dec2_lock_int (this, f)) {
2005           *add = f;
2006           add = &f->next;
2007           a++;
2008         }
2009       }
2010       keep[(img->is_first <= 0)] = img;
2011       img = img->next;
2012     }
2013     this->rp.last_flushed = keep[1];
2014     if (this->rp.last_flushed) {
2015       this->rp.last_flushed->next = NULL;
2016       if (!this->grab.last_frame) { /* rare late setting */
2017         vo_frame_inc_lock (this->rp.last_flushed);
2018         pthread_mutex_lock (&this->grab.lock);
2019         this->grab.last_frame = this->rp.last_flushed;
2020         pthread_mutex_unlock (&this->grab.lock);
2021       }
2022     }
2023     /* Override with first frame. */
2024     if (keep[0]) {
2025       keep[0]->vpts = *vpts;
2026       keep[0]->next = NULL;
2027       keep[0]->future_frame = NULL;
2028     }
2029     /* Free (almost) all at once. */
2030     *add = NULL;
2031     vo_free_append_list (this, freelist, add, a);
2032     /* Make sure clients dont miss this. */
2033     if (this->rp.need_flush_signal) {
2034       pthread_mutex_lock (&this->display_queue.mutex);
2035       pthread_cond_broadcast (&this->display_queue.done_flushing);
2036       pthread_mutex_unlock (&this->display_queue.mutex);
2037     }
2038     /* Report success. */
2039     if (n) {
2040       xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2041         "video_out: flushed out %d frames (now=%"PRId64", discard=%d).\n",
2042         n, *vpts, this->display_queue.discard_frames);
2043     }
2044     this->redraw_needed = 0;
2045     *vpts = 0;
2046     return keep[0];
2047   }
2048 
2049   ADD_READY_FRAMES;
2050   img = this->rp.ready_first;
2051 
2052   while (img) {
2053 
2054     if (img->is_first > 0) {
2055 #ifdef LOG_FLUSH
2056       printf ("video_out: first frame pts=%"PRId64", now=%"PRId64", discard=%d\n",
2057         img->vpts, *vpts, this->display_queue.discard_frames);
2058 #endif
2059       /* The user seek brake feature: display first frame after seek right now
2060        * (without "metronom prebuffering") if
2061        * - it is either no longer referenced by decoder or post layer, or
2062        * - it is due for display naturally, or
2063        * - we have waited too long for that to happen.
2064        * This shall do 3 things:
2065        * - User sees the effect of seek soon, and
2066        * - We dont decode too many frames in vain when there is a new seek, and
2067        * - We dont drop frames already decoded in time.
2068        * Finally, dont zero img->is_first so xine_play () gets woken up properly.
2069        */
2070       if ((img->lock_counter <= 2) || (img->vpts <= *vpts) || (img->is_first == 1)) {
2071         img->vpts = *vpts;
2072         *vpts = img->vpts + (img->duration ? img->duration : DEFAULT_FRAME_DURATION);
2073         break;
2074       }
2075       /* poll */
2076       lprintf ("frame still referenced %d times, is_first=%d\n", img->lock_counter, img->is_first);
2077       img->is_first--;
2078       *vpts += FIRST_FRAME_POLL_DELAY;
2079       /* At forward seek, fill the gap with last flushed frame if any. */
2080       if (this->rp.last_flushed && img->pts && this->rp.last_flushed->pts && (this->rp.last_flushed->pts < img->pts)) {
2081         img = this->rp.last_flushed;
2082         this->rp.last_flushed = NULL;
2083         img->vpts = *vpts;
2084         *vpts = img->vpts + (img->duration ? img->duration : DEFAULT_FRAME_DURATION);
2085         return img;
2086       }
2087       this->rp.wakeups_early++;
2088       return NULL;
2089     }
2090 
2091     {
2092       int64_t diff = *vpts - img->vpts, duration;
2093       if (diff < 0) {
2094         /* still too early for this frame */
2095         *vpts = img->vpts;
2096         this->rp.wakeups_early++;
2097         return NULL;
2098       }
2099       duration = img->duration ? img->duration
2100         : (img->next ? img->next->vpts - img->vpts : DEFAULT_FRAME_DURATION);
2101       if (diff <= duration) {
2102         /* OK, show this one */
2103         *vpts = img->vpts + duration;
2104         break;
2105       }
2106       xine_log (&this->xine->x, XINE_LOG_MSG,
2107         _("video_out: throwing away image with pts %" PRId64 " because it's too old (diff : %" PRId64 ").\n"),
2108         img->vpts, diff);
2109     }
2110 
2111     this->num_frames_discarded++;
2112 
2113     img = vo_ready_pop (this);
2114 
2115     if (img->stream) {
2116       xine_stream_private_t *m = (xine_stream_private_t *)img->stream;
2117       m = m->side_streams[0];
2118       xine_current_extra_info_set (m, img->extra_info);
2119     }
2120 
2121     ADD_READY_FRAMES;
2122 
2123     /* last frame? back it up for still frame creation */
2124     if (!this->rp.ready_first) {
2125       pthread_mutex_lock (&this->grab.lock);
2126       if (this->grab.last_frame) {
2127         lprintf ("overwriting frame backup\n");
2128         vo_frame_dec_lock (this->grab.last_frame);
2129       }
2130       lprintf ("possible still frame (old)\n");
2131       this->grab.last_frame = img;
2132       pthread_mutex_unlock (&this->grab.lock);
2133       vo_frame_dec_lock (img);
2134       /* wait 4 frames before drawing this one. this allow slower systems to recover. */
2135       this->redraw_needed = 4;
2136     } else {
2137       vo_frame_dec2_lock (this, img);
2138     }
2139 
2140     img = this->rp.ready_first;
2141   }
2142 
2143   if (img) {
2144     /* remove frame from display queue and show it */
2145     img->future_frame = img->next;
2146     img = vo_ready_pop (this);
2147     /* we dont need that filler anymore */
2148     if (this->rp.last_flushed) {
2149       vo_frame_dec2_lock (this, this->rp.last_flushed);
2150       this->rp.last_flushed = NULL;
2151     }
2152     return img;
2153   }
2154 
2155   lprintf ("no frame\n");
2156   check_redraw_needed (this, *vpts);
2157   *vpts = 0;
2158   return NULL;
2159 }
2160 
overlay_and_display_frame(vos_t * this,vo_frame_t * img,int64_t vpts)2161 static void overlay_and_display_frame (vos_t *this, vo_frame_t *img, int64_t vpts) {
2162 
2163   lprintf ("displaying image with vpts = %" PRId64 "\n", img->vpts);
2164 
2165   /* no, this is not were proc_*() is usually called.
2166    * it's just to catch special cases like late or duplicated frames.
2167    */
2168   if(!img->proc_called )
2169     vo_frame_driver_proc(img);
2170 
2171   if (img->stream) {
2172     xine_stream_private_t *m = (xine_stream_private_t *)img->stream;
2173     m = m->side_streams[0];
2174     /* Always post first frame time to make frontend relative seek work. */
2175     xine_current_extra_info_set (m, img->extra_info);
2176     /* First frame's native stream is the most common case.
2177      * Do it without streams lock.
2178      */
2179     if (img->is_first > 0) {
2180       pthread_mutex_lock (&m->first_frame.lock);
2181       if (m->first_frame.flag) {
2182         m->first_frame.flag = 0;
2183         pthread_cond_broadcast (&m->first_frame.reached);
2184       }
2185       pthread_mutex_unlock (&m->first_frame.lock);
2186     }
2187   }
2188 
2189   /* xine_play() may be called from a thread that has the display device locked
2190    * (eg an X window event handler). If it is waiting for a frame we better wake
2191    * it up _before_ we start displaying, or the first 10 seconds of video are lost.
2192    */
2193   if (img->is_first > 0) {
2194     xine_stream_private_t **s;
2195     xine_rwlock_rdlock (&this->streams_lock);
2196     for (s = this->streams; *s; s++) {
2197       xine_stream_private_t *m;
2198       if (&(*s)->s == img->stream)
2199         continue;
2200       m = (*s)->side_streams[0];
2201       pthread_mutex_lock (&m->first_frame.lock);
2202       if (m->first_frame.flag) {
2203         m->first_frame.flag = 0;
2204         pthread_cond_broadcast (&m->first_frame.reached);
2205       }
2206       pthread_mutex_unlock (&m->first_frame.lock);
2207     }
2208     xine_rwlock_unlock (&this->streams_lock);
2209     /* Dont signal the same frame again. */
2210     img->is_first = -1;
2211   }
2212 
2213   /* calling the frontend's frame output hook (via driver->display_frame () here)
2214    * while flushing (xine_stop ()) may freeze.
2215    */
2216   if (this->display_queue.discard_frames && (this->rp.ready_first || this->display_queue.first)) {
2217     img->free (img);
2218     this->redraw_needed = 0;
2219     return;
2220   }
2221 
2222   if (this->overlay_source) {
2223     this->overlay_source->multiple_overlay_blend (this->overlay_source,
2224 						  vpts,
2225 						  this->driver, img,
2226 						  this->video_loop_running && this->overlay_enabled);
2227   }
2228 
2229   this->driver->display_frame (this->driver, img);
2230 
2231   this->redraw_needed = 0;
2232 }
2233 
2234 /* special loop for paused mode
2235  * needed to update screen due overlay changes, resize, window
2236  * movement, brightness adjusting etc.
2237  */
paused_loop(vos_t * this,int64_t vpts)2238 static void paused_loop( vos_t *this, int64_t vpts )
2239 {
2240   /* prevent decoder thread from allocating too many new frames */
2241   vo_free_queue_read_lock (this);
2242 
2243   while (this->rp.speed == XINE_SPEED_PAUSE && this->video_loop_running) {
2244 
2245     ADD_READY_FRAMES;
2246 
2247     /* set last_frame to play the same frame several times */
2248     if (!this->grab.last_frame) {
2249       vo_frame_t *f;
2250       f = this->rp.ready_first;
2251       if (f) {
2252         vo_frame_inc_lock (f);
2253         pthread_mutex_lock (&this->grab.lock);
2254         this->grab.last_frame = f;
2255         pthread_mutex_unlock (&this->grab.lock);
2256         this->redraw_needed = 1;
2257       }
2258     }
2259 
2260     /* what a terrible HACK.
2261      * For single step mode, keep the engine paused all the time, as audio out
2262      * seems unable to pause that quickly. Instead, advance manually and nudge
2263      * that master clock. After this, audio out will get this message as well.
2264      */
2265     {
2266       vo_frame_t *f = NULL;
2267 
2268       if (this->trigger_drawing.step) {
2269         pthread_mutex_lock (&this->trigger_drawing.mutex);
2270         if (this->trigger_drawing.step) {
2271           if (this->rp.ready_first) {
2272             f = vo_ready_pop (this);
2273             f->future_frame = this->rp.ready_first;
2274             this->trigger_drawing.step = 0;
2275             pthread_cond_broadcast (&this->trigger_drawing.done_stepping);
2276           }
2277         }
2278         this->rp.speed = this->trigger_drawing.speed;
2279         pthread_mutex_unlock (&this->trigger_drawing.mutex);
2280 
2281         if (f) {
2282           vpts = f->vpts;
2283           this->clock->adjust_clock (this->clock, vpts);
2284           xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2285             "video_out: SINGLE_STEP: vpts %"PRId64".\n", vpts);
2286           overlay_and_display_frame (this, f, vpts);
2287           vo_grab_current_frame (this, f, vpts);
2288         }
2289       }
2290 
2291       /* refresh output */
2292       if (!f) {
2293         check_redraw_needed (this, vpts);
2294         if (this->redraw_needed) {
2295           f = duplicate_frame (this, this->grab.last_frame);
2296           if (f) {
2297             vo_reref (this, f);
2298             f->vpts = vpts;
2299             overlay_and_display_frame (this, f, vpts);
2300           }
2301         }
2302       }
2303     }
2304 
2305     /* wait for 1/25s or wakeup */
2306     this->rp.now.tv_nsec += this->rp.poll_time * 1000;
2307     if (this->rp.now.tv_nsec >= 1000000000) {
2308       /* resyncing the pause clock every second should be enough ;-) */
2309       xine_gettime (&this->rp.now);
2310       this->rp.now.tv_nsec += this->rp.poll_time * 1000;
2311       if (this->rp.now.tv_nsec >= 1000000000) {
2312         this->rp.now.tv_sec++;
2313         this->rp.now.tv_nsec -= 1000000000;
2314       }
2315     }
2316     pthread_mutex_lock (&this->trigger_drawing.mutex);
2317     if (!this->trigger_drawing.draw) {
2318       struct timespec ts = this->rp.now;
2319       pthread_cond_timedwait (&this->trigger_drawing.wake, &this->trigger_drawing.mutex, &ts);
2320     }
2321     if (this->trigger_drawing.draw) {
2322       this->trigger_drawing.draw = 0;
2323       this->redraw_needed = 1;
2324       /* no timeout, resync clock */
2325       this->rp.now.tv_nsec = 990000000;
2326     }
2327     this->rp.speed = this->trigger_drawing.speed;
2328     pthread_mutex_unlock (&this->trigger_drawing.mutex);
2329 
2330     /* flush when requested */
2331     if (this->display_queue.discard_frames) {
2332       vo_frame_t *img = vo_ready_get_all (this);
2333       vo_list_flush (this, img);
2334       if (this->rp.need_flush_signal) {
2335         pthread_mutex_lock (&this->display_queue.mutex);
2336         pthread_cond_broadcast (&this->display_queue.done_flushing);
2337         pthread_mutex_unlock (&this->display_queue.mutex);
2338       }
2339     }
2340   }
2341 
2342   vo_free_queue_read_unlock (this);
2343 }
2344 
video_out_update_disable_flush_from_video_out(void * this_gen,xine_cfg_entry_t * entry)2345 static void video_out_update_disable_flush_from_video_out(void *this_gen, xine_cfg_entry_t *entry) {
2346   vos_t *this = (vos_t *)this_gen;
2347   this->disable_decoder_flush_from_video_out = entry->num_value;
2348 }
2349 
video_out_loop(void * this_gen)2350 static void *video_out_loop (void *this_gen) {
2351   vos_t *this = (vos_t *) this_gen;
2352 
2353 #ifndef WIN32
2354   errno = 0;
2355   if (nice(-2) == -1 && errno)
2356     xine_log(&this->xine->x, XINE_LOG_MSG, "video_out: can't raise nice priority by 2: %s\n", strerror(errno));
2357 #endif /* WIN32 */
2358 
2359   this->disable_decoder_flush_from_video_out = this->xine->x.config->register_bool (this->xine->x.config,
2360     "engine.decoder.disable_flush_from_video_out", 0,
2361     _("disable decoder flush from video out"),
2362     _("video out causes a decoder flush when video out runs out of frames for displaying,\n"
2363       "because the decoder hasn't deliverd new frames for quite a while.\n"
2364       "flushing the decoder causes decoding errors for images decoded after the flush.\n"
2365       "to avoid the decoding errors, decoder flush at video out should be disabled.\n\n"
2366       "WARNING: as the flush was introduced to fix some issues when playing DVD still images, it is\n"
2367       "likely that these issues may reappear in case they haven't been fixed differently meanwhile.\n"),
2368     20, video_out_update_disable_flush_from_video_out, this);
2369 
2370   /*
2371    * here it is - the heart of xine (or rather: one of the hearts
2372    * of xine) : the video output loop
2373    */
2374 
2375   lprintf ("loop starting...\n");
2376 
2377   pthread_mutex_lock (&this->trigger_drawing.mutex);
2378   this->rp.speed = this->trigger_drawing.speed;
2379   pthread_mutex_unlock (&this->trigger_drawing.mutex);
2380 
2381   while ( this->video_loop_running ) {
2382     int64_t vpts, next_frame_vpts;
2383     int64_t usec_to_sleep;
2384 
2385     /* record current time as both speed dependent virtual presentation timestamp (vpts)
2386      * and absolute system time, and hope these are halfway in sync.
2387      */
2388     vpts = next_frame_vpts = this->clock->get_current_time (this->clock);
2389     xine_gettime (&this->rp.now);
2390     lprintf ("loop iteration at %" PRId64 "\n", vpts);
2391 
2392     this->rp.wakeups_total++;
2393 
2394     {
2395       /* find frame to display */
2396       vo_frame_t *img = next_frame (this, &next_frame_vpts);
2397       /* if we have found a frame, display it */
2398       if (img) {
2399         lprintf ("displaying frame (id=%d)\n", img->id);
2400         overlay_and_display_frame (this, img, vpts);
2401         vo_grab_current_frame (this, img, vpts);
2402       } else if (this->redraw_needed) {
2403         if (this->grab.last_frame && (this->redraw_needed == 1)) {
2404           lprintf ("generating still frame (vpts = %" PRId64 ") \n", vpts);
2405           /* keep playing still frames */
2406           img = duplicate_frame (this, this->grab.last_frame);
2407           if (img) {
2408             vo_reref (this, img);
2409             img->vpts = vpts;
2410             overlay_and_display_frame (this, img, vpts);
2411           }
2412         } else {
2413           lprintf ("no frame, but no backup frame\n");
2414           this->redraw_needed--;
2415         }
2416       }
2417     }
2418 
2419     /*
2420      * if we haven't heared from the decoder for some time
2421      * flush it
2422      * test display fifo empty to protect from deadlocks
2423      */
2424 
2425     if ((vpts - this->last_delivery_pts > 30000) &&
2426         !this->display_queue.first && !this->rp.ready_first) {
2427       if (this->last_delivery_pts && !this->disable_decoder_flush_from_video_out) {
2428         xine_stream_private_t **s;
2429         xine_rwlock_rdlock (&this->streams_lock);
2430         for (s = this->streams; *s; s++) {
2431           if ((*s)->video_decoder_plugin && (*s)->s.video_fifo) {
2432             buf_element_t *buf;
2433             lprintf ("flushing current video decoder plugin\n");
2434             buf = (*s)->s.video_fifo->buffer_pool_try_alloc ((*s)->s.video_fifo);
2435             if (buf) {
2436               buf->type = BUF_CONTROL_FLUSH_DECODER;
2437               (*s)->s.video_fifo->insert ((*s)->s.video_fifo, buf);
2438             }
2439           }
2440         }
2441         xine_rwlock_unlock (&this->streams_lock);
2442       }
2443       this->last_delivery_pts = vpts;
2444     }
2445 
2446     /* now the time critical stuff is done */
2447     ADD_READY_FRAMES;
2448 
2449     /*
2450      * wait until it's time to display next frame
2451      */
2452 
2453     lprintf ("next_frame_vpts is %" PRId64 "\n", next_frame_vpts);
2454     if ((next_frame_vpts - vpts) > 2 * 90000) {
2455       xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2456       "video_out: vpts/clock error, next_vpts=%" PRId64 " cur_vpts=%" PRId64 "\n", next_frame_vpts, vpts);
2457       if (this->rp.ready_first && this->rp.ready_first->next) {
2458         int64_t d = this->rp.ready_first->next->vpts - vpts;
2459         if ((d >= 0) && (d <= 2 * 90000)) {
2460           d = (d >> 1) + vpts;
2461           xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2462             "video_out: looks like a missed decoder flush, fixing next_vpts to %" PRId64 ".\n", d);
2463           this->rp.ready_first->vpts = d;
2464           next_frame_vpts = d;
2465         }
2466       }
2467     }
2468 
2469     /* get diff time for next iteration */
2470     if (next_frame_vpts && this->rp.speed > 0)
2471       usec_to_sleep = (next_frame_vpts - vpts) * 100 * XINE_FINE_SPEED_NORMAL / (9 * this->rp.speed);
2472     else
2473       /* we don't know when the next frame is due, only wait a little */
2474       usec_to_sleep = this->rp.poll_time;
2475 
2476     while (this->video_loop_running) {
2477       int timedout, wait;
2478 
2479       if (this->display_queue.discard_frames && (this->rp.ready_first || this->display_queue.first))
2480         break;
2481 
2482       if (this->rp.speed == XINE_SPEED_PAUSE) {
2483         paused_loop (this, vpts);
2484         break;
2485       }
2486 
2487       /* limit usec_to_sleep to maintain responsiveness */
2488       wait = usec_to_sleep;
2489       if (wait <= 0)
2490         break;
2491       if (wait > this->rp.poll_limit)
2492         wait = this->rp.poll_limit;
2493 
2494       lprintf ("%d usec to sleep at master vpts %" PRId64 "\n", wait, vpts);
2495 
2496       /* next stop absolute time */
2497       this->rp.now.tv_nsec += wait * 1000;
2498       if (this->rp.now.tv_nsec >= 1000000000) {
2499         this->rp.now.tv_sec++;
2500         this->rp.now.tv_nsec -= 1000000000;
2501       }
2502       usec_to_sleep -= wait;
2503 
2504       timedout = 0;
2505       pthread_mutex_lock (&this->trigger_drawing.mutex);
2506       if (!this->trigger_drawing.draw) {
2507         struct timespec abstime = this->rp.now;
2508         timedout = pthread_cond_timedwait (&this->trigger_drawing.wake, &this->trigger_drawing.mutex, &abstime);
2509       }
2510       this->rp.speed = this->trigger_drawing.speed;
2511       this->trigger_drawing.draw = 0;
2512       pthread_mutex_unlock (&this->trigger_drawing.mutex);
2513       /* honor trigger update only when a backup img is available */
2514       if (!timedout && this->grab.last_frame)
2515         break;
2516     }
2517   }
2518 
2519   /*
2520    * throw away undisplayed frames
2521    */
2522 
2523   {
2524     vo_frame_t *img = vo_ready_get_all (this);
2525     vo_list_flush (this, img);
2526   }
2527 
2528   /* dont let folks wait forever in vain */
2529 
2530   pthread_mutex_lock (&this->display_queue.mutex);
2531   if (this->display_queue.discard_frames)
2532     pthread_cond_broadcast (&this->display_queue.done_flushing);
2533   pthread_mutex_unlock (&this->display_queue.mutex);
2534 
2535   pthread_mutex_lock (&this->trigger_drawing.mutex);
2536   if (this->trigger_drawing.step) {
2537     this->trigger_drawing.step = 0;
2538     pthread_cond_broadcast (&this->trigger_drawing.done_stepping);
2539   }
2540   pthread_mutex_unlock (&this->trigger_drawing.mutex);
2541 
2542   if (this->rp.last_flushed) {
2543     vo_frame_dec2_lock (this, this->rp.last_flushed);
2544     this->rp.last_flushed = NULL;
2545   }
2546 
2547   pthread_mutex_lock(&this->grab.lock);
2548   if (this->grab.last_frame) {
2549     vo_frame_dec_lock( this->grab.last_frame );
2550     this->grab.last_frame = NULL;
2551   }
2552   pthread_mutex_unlock(&this->grab.lock);
2553 
2554   this->xine->x.config->unregister_callbacks (this->xine->x.config, NULL, NULL, this, sizeof (*this));
2555 
2556   return NULL;
2557 }
2558 
2559 /*
2560  * public function for video processing frontends to manually
2561  * consume video frames
2562  */
2563 
xine_get_next_video_frame(xine_video_port_t * this_gen,xine_video_frame_t * frame)2564 int xine_get_next_video_frame (xine_video_port_t *this_gen, xine_video_frame_t *frame) {
2565   vos_t *this = (vos_t *)this_gen;
2566   vo_frame_t *img;
2567   struct timespec now = {0, 990000000};
2568 
2569   pthread_mutex_lock (&this->display_queue.mutex);
2570 
2571   while (!this->display_queue.first) {
2572     {
2573       xine_stream_private_t *stream = this->streams[0];
2574       if (stream && (stream->s.video_fifo->fifo_size == 0)
2575         && (stream->demux.plugin->get_status (stream->demux.plugin) != DEMUX_OK)) {
2576         /* no further data can be expected here */
2577         pthread_mutex_unlock (&this->display_queue.mutex);
2578         return 0;
2579       }
2580     }
2581 
2582     now.tv_nsec += 20000000;
2583     if (now.tv_nsec >= 1000000000) {
2584       xine_gettime (&now);
2585       now.tv_nsec += 20000000;
2586       if (now.tv_nsec >= 1000000000) {
2587         now.tv_sec++;
2588         now.tv_nsec -= 1000000000;
2589       }
2590     }
2591     {
2592       struct timespec ts = now;
2593       pthread_cond_timedwait (&this->display_queue.not_empty, &this->display_queue.mutex, &ts);
2594     }
2595   }
2596 
2597   /*
2598    * remove frame from display queue and return it
2599    */
2600 
2601   img = vo_display_queue_pop_int (this);
2602   pthread_mutex_unlock(&this->display_queue.mutex);
2603 
2604   frame->vpts         = img->vpts;
2605   frame->duration     = img->duration;
2606   frame->width        = img->width;
2607   frame->height       = img->height;
2608   frame->pos_stream   = img->extra_info->input_normpos;
2609   frame->pos_time     = img->extra_info->input_time;
2610   frame->frame_number = img->extra_info->frame_number;
2611   frame->aspect_ratio = img->ratio;
2612   frame->colorspace   = img->format;
2613   frame->data         = img->base[0];
2614   frame->xine_frame   = img;
2615 
2616   return 1;
2617 }
2618 
xine_free_video_frame(xine_video_port_t * port,xine_video_frame_t * frame)2619 void xine_free_video_frame (xine_video_port_t *port,
2620 			    xine_video_frame_t *frame) {
2621 
2622   vo_frame_t *img = (vo_frame_t *) frame->xine_frame;
2623   vos_t *this = (vos_t *)img->port;
2624 
2625   (void)port;
2626   vo_frame_dec2_lock (this, img);
2627 }
2628 
2629 
2630 /********************************************************************
2631  * external API                                                     *
2632  *******************************************************************/
2633 
vo_get_capabilities(xine_video_port_t * this_gen)2634 static uint32_t vo_get_capabilities (xine_video_port_t *this_gen) {
2635   vos_t      *this = (vos_t *) this_gen;
2636   return this->driver->get_capabilities (this->driver);
2637 }
2638 
vo_open(xine_video_port_t * this_gen,xine_stream_t * stream)2639 static void vo_open (xine_video_port_t *this_gen, xine_stream_t *stream) {
2640 
2641   vos_t      *this = (vos_t *) this_gen;
2642 
2643   xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: vo_open (%p)\n", (void*)stream);
2644 
2645   this->video_opened = 1;
2646   pthread_mutex_lock (&this->display_queue.mutex);
2647   this->display_queue.discard_frames = 0;
2648   this->display_queue.flushed = 1; /* see vo_frame_draw () */
2649   pthread_mutex_unlock (&this->display_queue.mutex);
2650   this->last_delivery_pts = 0;
2651   this->warn_threshold_event_sent = this->warn_threshold_exceeded = 0;
2652   if (!this->overlay_enabled && (stream == XINE_ANON_STREAM || stream == NULL || stream->spu_channel_user > -2))
2653     /* enable overlays if our new stream might want to show some */
2654     this->overlay_enabled = 1;
2655 
2656   vo_streams_register (this, (xine_stream_private_t *)stream);
2657   vo_unref_obsolete (this);
2658 }
2659 
vo_close(xine_video_port_t * this_gen,xine_stream_t * stream)2660 static void vo_close (xine_video_port_t *this_gen, xine_stream_t *stream) {
2661 
2662   vos_t      *this = (vos_t *) this_gen;
2663 
2664   xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: vo_close (%p)\n", (void*)stream);
2665 
2666   /* this will make sure all hide events were processed */
2667   if (this->overlay_source)
2668     this->overlay_source->flush_events (this->overlay_source);
2669 
2670   this->video_opened = 0;
2671 
2672   /* unregister stream */
2673   vo_streams_unregister (this, (xine_stream_private_t *)stream);
2674 }
2675 
2676 
vo_get_property(xine_video_port_t * this_gen,int property)2677 static int vo_get_property (xine_video_port_t *this_gen, int property) {
2678   vos_t *this = (vos_t *) this_gen;
2679   int ret;
2680 
2681   switch (property) {
2682   case XINE_PARAM_VO_SINGLE_STEP:
2683     ret = 0;
2684     break;
2685 
2686   case VO_PROP_DISCARD_FRAMES:
2687     ret = this->display_queue.discard_frames;
2688     break;
2689 
2690   case VO_PROP_BUFS_IN_FIFO:
2691     ret = this->video_loop_running ? this->display_queue.num_buffers + this->rp.ready_num : -1;
2692     break;
2693 
2694   case VO_PROP_BUFS_FREE:
2695     ret = this->video_loop_running ? this->free_queue.num_buffers : -1;
2696     break;
2697 
2698   case VO_PROP_BUFS_TOTAL:
2699     ret = this->video_loop_running ? this->free_queue.num_buffers_max : -1;
2700     break;
2701 
2702   case VO_PROP_NUM_STREAMS:
2703     xine_rwlock_rdlock (&this->streams_lock);
2704     ret = this->num_null_streams + this->num_anon_streams + this->num_streams;
2705     xine_rwlock_unlock (&this->streams_lock);
2706     break;
2707 
2708   /*
2709    * handle XINE_PARAM_xxx properties (convert from driver's range)
2710    */
2711   case XINE_PARAM_VO_CROP_LEFT:
2712     ret = this->crop_left;
2713     break;
2714   case XINE_PARAM_VO_CROP_RIGHT:
2715     ret = this->crop_right;
2716     break;
2717   case XINE_PARAM_VO_CROP_TOP:
2718     ret = this->crop_top;
2719     break;
2720   case XINE_PARAM_VO_CROP_BOTTOM:
2721     ret = this->crop_bottom;
2722     break;
2723 
2724   case XINE_PARAM_VO_SHARPNESS:
2725   case XINE_PARAM_VO_NOISE_REDUCTION:
2726   case XINE_PARAM_VO_HUE:
2727   case XINE_PARAM_VO_SATURATION:
2728   case XINE_PARAM_VO_CONTRAST:
2729   case XINE_PARAM_VO_BRIGHTNESS:
2730   case XINE_PARAM_VO_GAMMA:
2731    {
2732     int v, min_v, max_v, range_v;
2733 
2734     pthread_mutex_lock( &this->driver_lock );
2735     this->driver->get_property_min_max (this->driver,
2736 					property & 0xffffff,
2737 					&min_v, &max_v);
2738 
2739     v = this->driver->get_property (this->driver, property & 0xffffff);
2740 
2741     range_v = max_v - min_v + 1;
2742 
2743     if (range_v > 0)
2744       ret = ((v-min_v) * 65536 + 32768) / range_v;
2745     else
2746       ret = 0;
2747     pthread_mutex_unlock( &this->driver_lock );
2748   }
2749     break;
2750 
2751   default:
2752     pthread_mutex_lock( &this->driver_lock );
2753     ret = this->driver->get_property(this->driver, property & 0xffffff);
2754     pthread_mutex_unlock( &this->driver_lock );
2755   }
2756   return ret;
2757 }
2758 
vo_set_property(xine_video_port_t * this_gen,int property,int value)2759 static int vo_set_property (xine_video_port_t *this_gen, int property, int value) {
2760   vos_t *this = (vos_t *) this_gen;
2761   int ret;
2762 
2763   switch (property) {
2764 
2765   case XINE_PARAM_VO_SINGLE_STEP:
2766     ret = !!value;
2767     if (this->grab_only)
2768       break;
2769     /* xine_set_param () will (un)pause for us here to avoid ticket freeze. */
2770     pthread_mutex_lock (&this->trigger_drawing.mutex);
2771     this->trigger_drawing.step = ret;
2772     this->trigger_drawing.draw = 0;
2773     pthread_cond_signal (&this->trigger_drawing.wake);
2774     if (ret) {
2775       struct timespec ts = {0, 0};
2776       xine_gettime (&ts);
2777       ts.tv_nsec += 500000000;
2778       if (ts.tv_nsec >= 1000000000) {
2779         ts.tv_sec++;
2780         ts.tv_nsec -= 1000000000;
2781       }
2782       if (pthread_cond_timedwait (&this->trigger_drawing.done_stepping, &this->trigger_drawing.mutex, &ts))
2783         ret = 0;
2784     }
2785     pthread_mutex_unlock (&this->trigger_drawing.mutex);
2786     break;
2787 
2788   case VO_PROP_DISCARD_FRAMES:
2789     /* recursive discard frames setting */
2790     if (value) {
2791       pthread_mutex_lock (&this->display_queue.mutex);
2792       this->display_queue.discard_frames++;
2793       ret = this->display_queue.discard_frames;
2794       if (this->grab_only) {
2795         /* discard buffers here because we have no output thread. */
2796         vo_manual_flush (this);
2797         pthread_mutex_unlock (&this->display_queue.mutex);
2798       } else {
2799         pthread_mutex_unlock (&this->display_queue.mutex);
2800         if (ret == 1) {
2801           /* render thread will grab this mutex after each frame.
2802            * taking it here triggers a data cache sync, and makes it see discard_frames early. */
2803           pthread_mutex_lock (&this->trigger_drawing.mutex);
2804           this->trigger_drawing.draw = 1;
2805           pthread_cond_signal (&this->trigger_drawing.wake);
2806           pthread_mutex_unlock (&this->trigger_drawing.mutex);
2807         }
2808       }
2809     } else {
2810       pthread_mutex_lock (&this->display_queue.mutex);
2811       if (this->display_queue.discard_frames) {
2812         if (this->display_queue.discard_frames == 1) {
2813           if (this->video_loop_running && (this->display_queue.flush_extra || this->display_queue.first)) {
2814             /* Usually, render thread already did that in the meantime. Anyway, make sure display queue
2815                is empty, and more importantly, there are free frames for decoding when discard gets lifted. */
2816             vo_wait_flush (this);
2817           }
2818           this->display_queue.flushed = 1;
2819         }
2820         this->display_queue.discard_frames--;
2821         ret = this->display_queue.discard_frames;
2822         pthread_mutex_unlock (&this->display_queue.mutex);
2823       } else {
2824         pthread_mutex_unlock (&this->display_queue.mutex);
2825         xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2826           "vo_set_property: discard_frames is already zero\n");
2827         ret = 0;
2828       }
2829     }
2830     break;
2831 
2832   /*
2833    * handle XINE_PARAM_xxx properties (convert to driver's range)
2834    */
2835   case XINE_PARAM_VO_CROP_LEFT:
2836     if( value < 0 )
2837       value = 0;
2838     ret = this->crop_left = value;
2839     break;
2840   case XINE_PARAM_VO_CROP_RIGHT:
2841     if( value < 0 )
2842       value = 0;
2843     ret = this->crop_right = value;
2844     break;
2845   case XINE_PARAM_VO_CROP_TOP:
2846     if( value < 0 )
2847       value = 0;
2848     ret = this->crop_top = value;
2849     break;
2850   case XINE_PARAM_VO_CROP_BOTTOM:
2851     if( value < 0 )
2852       value = 0;
2853     ret = this->crop_bottom = value;
2854     break;
2855 
2856   case XINE_PARAM_VO_SHARPNESS:
2857   case XINE_PARAM_VO_NOISE_REDUCTION:
2858   case XINE_PARAM_VO_HUE:
2859   case XINE_PARAM_VO_SATURATION:
2860   case XINE_PARAM_VO_CONTRAST:
2861   case XINE_PARAM_VO_BRIGHTNESS:
2862   case XINE_PARAM_VO_GAMMA:
2863     if (!this->grab_only) {
2864       int v, min_v, max_v, range_v;
2865 
2866       pthread_mutex_lock( &this->driver_lock );
2867 
2868       this->driver->get_property_min_max (this->driver,
2869 					property & 0xffffff,
2870 					&min_v, &max_v);
2871 
2872       range_v = max_v - min_v + 1;
2873 
2874       v = (value * range_v + (range_v/2)) / 65536 + min_v;
2875 
2876       this->driver->set_property(this->driver, property & 0xffffff, v);
2877       pthread_mutex_unlock( &this->driver_lock );
2878       ret = value;
2879     } else
2880       ret = 0;
2881     break;
2882 
2883 
2884   default:
2885     if (!this->grab_only) {
2886       pthread_mutex_lock( &this->driver_lock );
2887       ret =  this->driver->set_property(this->driver, property & 0xffffff, value);
2888       pthread_mutex_unlock( &this->driver_lock );
2889     } else
2890       ret = 0;
2891   }
2892 
2893   return ret;
2894 }
2895 
vo_status(xine_video_port_t * this_gen,xine_stream_t * s,int * width,int * height,int64_t * img_duration)2896 static int vo_status (xine_video_port_t *this_gen, xine_stream_t *s,
2897                       int *width, int *height, int64_t *img_duration) {
2898   vos_t      *this = (vos_t *) this_gen;
2899   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2900 
2901   if (!stream || (&stream->s == XINE_ANON_STREAM)) {
2902     *width = this->current_width;
2903     *height = this->current_height;
2904     *img_duration = this->current_duration;
2905     return 0;
2906   }
2907 
2908   xine_rwlock_rdlock (&this->streams_lock);
2909   {
2910     xine_stream_private_t **s;
2911     for (s = this->streams; *s; s++) {
2912       if (*s == stream) {
2913         *width = this->current_width;
2914         *height = this->current_height;
2915         *img_duration = this->current_duration;
2916         xine_rwlock_unlock (&this->streams_lock);
2917         return 1;
2918       }
2919     }
2920   }
2921   xine_rwlock_unlock(&this->streams_lock);
2922   return 0;
2923 }
2924 
vo_speed_change_cb(void * this_gen,int new_speed)2925 static void vo_speed_change_cb (void *this_gen, int new_speed) {
2926   vos_t *this = this_gen;
2927 
2928   pthread_mutex_lock (&this->trigger_drawing.mutex);
2929   /* something to do? */
2930   if (new_speed == this->trigger_drawing.speed) {
2931     pthread_mutex_unlock (&this->trigger_drawing.mutex);
2932     return;
2933   }
2934   /* bother render thread when (un)pauseing, or when increasing speed significantly
2935    * (display next frame earlier). */
2936   if ((new_speed <= 0) || (this->trigger_drawing.speed <= 0) ||
2937     (new_speed > this->trigger_drawing.speed + XINE_FINE_SPEED_NORMAL / 20)) {
2938     this->trigger_drawing.draw = 1;
2939     pthread_cond_signal (&this->trigger_drawing.wake);
2940   }
2941   this->trigger_drawing.speed = new_speed;
2942   pthread_mutex_unlock (&this->trigger_drawing.mutex);
2943   xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: new speed %d.\n", new_speed);
2944 }
2945 
vo_exit(xine_video_port_t * this_gen)2946 static void vo_exit (xine_video_port_t *this_gen) {
2947 
2948   vos_t      *this = (vos_t *) this_gen;
2949 
2950   xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: exit.\n");
2951 
2952   this->xine->port_ticket->revoke_cb_unregister (this->xine->port_ticket, vo_ticket_revoked, this);
2953 
2954   if (this->video_loop_running) {
2955     void *p;
2956 
2957     this->clock->unregister_speed_change_callback (this->clock, vo_speed_change_cb, this);
2958 
2959     /* make render thread see that early. */
2960     pthread_mutex_lock (&this->trigger_drawing.mutex);
2961     this->video_loop_running = 0;
2962     this->trigger_drawing.draw = 1;
2963     pthread_cond_signal (&this->trigger_drawing.wake);
2964     pthread_mutex_unlock (&this->trigger_drawing.mutex);
2965 
2966     pthread_join (this->video_thread, &p);
2967   }
2968 
2969   {
2970     int n = this->driver->set_property (this->driver, VO_PROP_DISCARD_FRAMES, -1);
2971     if (n > 0)
2972       xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2973         "video_out: returned %d held frames from driver.\n", n);
2974   }
2975 
2976   {
2977     vo_frame_t *list = vo_free_queue_get_all (this), *img;
2978     vo_unref_list (this, list);
2979     for (img = list; img; img = img->next) {
2980       int i;
2981       for (i = 0; i < this->frames_total; i++) {
2982         if (this->display_queue.frames[i] == img) {
2983           this->display_queue.frames[i] = NULL;
2984           break;
2985         }
2986       }
2987     }
2988     vo_dispose_list (list);
2989   }
2990   {
2991     int i;
2992     for (i = 0; i < this->frames_total; i++) {
2993       if (this->display_queue.frames[i]) {
2994         xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG,
2995           "video_out: BUG: frame #%d (%p) still in use (%d refs).\n",
2996           i, (void*)this->display_queue.frames[i], this->display_queue.frames[i]->lock_counter);
2997       }
2998     }
2999   }
3000   vo_dispose_list (vo_display_queue_get_all (this));
3001 
3002   /* print frame usage stats */
3003   xprintf (&this->xine->x, XINE_VERBOSITY_LOG, _("video_out: max frames used: %d of %d\n"),
3004     this->frames_peak_used, this->frames_total);
3005   xprintf (&this->xine->x, XINE_VERBOSITY_LOG, _("video_out: early wakeups: %d of %d\n"),
3006     this->rp.wakeups_early, this->rp.wakeups_total);
3007 
3008 
3009   _x_free_video_driver(&this->xine->x, &this->driver);
3010 
3011   xine_freep_aligned (&this->display_queue.frames);
3012 
3013   if (this->overlay_source) {
3014     this->overlay_source->dispose (this->overlay_source);
3015   }
3016 
3017   vo_streams_close (this);
3018 
3019   vo_free_queue_close (this);
3020   vo_display_queue_close (this);
3021 
3022   pthread_cond_destroy (&this->trigger_drawing.done_stepping);
3023   pthread_cond_destroy (&this->trigger_drawing.wake);
3024   pthread_mutex_destroy (&this->trigger_drawing.mutex);
3025 
3026   pthread_mutex_destroy (&this->driver_lock);
3027 
3028   pthread_mutex_destroy(&this->grab.lock);
3029   pthread_cond_destroy(&this->grab.wake);
3030 
3031   lprintf ("vo_exit... done\n");
3032 
3033   free (this);
3034 }
3035 
vo_get_last_frame(xine_video_port_t * this_gen)3036 static vo_frame_t *vo_get_last_frame (xine_video_port_t *this_gen) {
3037   vos_t      *this = (vos_t *) this_gen;
3038   vo_frame_t *last_frame;
3039 
3040   pthread_mutex_lock(&this->grab.lock);
3041 
3042   last_frame = this->grab.last_frame;
3043   if (last_frame)
3044     vo_frame_inc_lock(last_frame);
3045 
3046   pthread_mutex_unlock(&this->grab.lock);
3047 
3048   return last_frame;
3049 }
3050 
3051 /* overlay stuff */
3052 
vo_get_overlay_manager(xine_video_port_t * this_gen)3053 static video_overlay_manager_t *vo_get_overlay_manager (xine_video_port_t *this_gen) {
3054   vos_t      *this = (vos_t *) this_gen;
3055   return this->overlay_source;
3056 }
3057 
vo_enable_overlay(xine_video_port_t * this_gen,int overlay_enabled)3058 static void vo_enable_overlay (xine_video_port_t *this_gen, int overlay_enabled) {
3059   vos_t      *this = (vos_t *) this_gen;
3060 
3061   if (overlay_enabled) {
3062     /* we always ENable ... */
3063     this->overlay_enabled = 1;
3064   } else {
3065     /* ... but we only actually DISable, if all associated streams have SPU off */
3066     xine_stream_private_t **s;
3067     xine_rwlock_rdlock (&this->streams_lock);
3068     if (this->num_anon_streams > 0) {
3069       xine_rwlock_unlock (&this->streams_lock);
3070       return;
3071     }
3072     for (s = this->streams; *s; s++) {
3073       if ((*s)->s.spu_channel_user > -2) {
3074         xine_rwlock_unlock (&this->streams_lock);
3075 	return;
3076       }
3077     }
3078     xine_rwlock_unlock (&this->streams_lock);
3079     this->overlay_enabled = 0;
3080   }
3081 }
3082 
3083 /*
3084  * Flush video_out fifo
3085  */
vo_flush(xine_video_port_t * this_gen)3086 static void vo_flush (xine_video_port_t *this_gen) {
3087   vos_t      *this = (vos_t *) this_gen;
3088 
3089   if (this->video_loop_running) {
3090     pthread_mutex_lock (&this->display_queue.mutex);
3091     this->display_queue.discard_frames++;
3092     vo_wait_flush (this);
3093     if (this->display_queue.discard_frames > 0)
3094       this->display_queue.discard_frames--;
3095     pthread_mutex_unlock (&this->display_queue.mutex);
3096   } else {
3097     vo_manual_flush (this);
3098   }
3099 }
3100 
vo_trigger_drawing(xine_video_port_t * this_gen)3101 static void vo_trigger_drawing (xine_video_port_t *this_gen) {
3102   vos_t      *this = (vos_t *) this_gen;
3103 
3104   pthread_mutex_lock (&this->trigger_drawing.mutex);
3105   this->trigger_drawing.draw = 1;
3106   pthread_cond_signal (&this->trigger_drawing.wake);
3107   pthread_mutex_unlock (&this->trigger_drawing.mutex);
3108 }
3109 
_x_vo_new_port(xine_t * xine,vo_driver_t * driver,int grabonly)3110 xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabonly) {
3111   vos_t *this;
3112   int    num_frame_buffers;
3113 
3114   this = calloc(1, sizeof(vos_t)) ;
3115   if (!this)
3116     return NULL;
3117 #ifndef HAVE_ZERO_SAFE_MEM
3118   /* Do these first, when compiler still knows "this" is all zeroed.
3119    * Let it optimize away this on most systems where clear mem
3120    * interpretes as 0, 0f or NULL safely.
3121    */
3122   this->num_frames_delivered  = 0;
3123   this->num_frames_skipped    = 0;
3124   this->num_frames_discarded  = 0;
3125   this->grab_only             = 0;
3126   this->video_opened          = 0;
3127   this->video_loop_running    = 0;
3128   this->trigger_drawing.draw  = 0;
3129   this->trigger_drawing.step  = 0;
3130   this->grab.last_frame       = NULL;
3131   this->grab.request          = NULL;
3132   this->frames_extref         = 0;
3133   this->frames_peak_used      = 0;
3134   this->frame_drop_cpt        = 0;
3135   this->frame_drop_suggested  = 0;
3136   this->rp.ready_first        = NULL;
3137   this->rp.ready_num          = 0;
3138   this->rp.need_flush_signal  = 0;
3139   this->rp.last_flushed       = NULL;
3140 #  ifdef ADD_KEYFRAME_INDEX
3141   this->keyframe_mode         = 0;
3142 #  endif
3143 #endif
3144 
3145   this->xine   = (xine_private_t *)xine;
3146   this->clock  = xine->clock;
3147   this->driver = driver;
3148   this->display_queue.flushed = 1;
3149 
3150   this->vo.open                  = vo_open;
3151   this->vo.get_frame             = vo_get_frame;
3152   this->vo.get_last_frame        = vo_get_last_frame;
3153   this->vo.new_grab_video_frame  = vo_new_grab_video_frame;
3154   this->vo.close                 = vo_close;
3155   this->vo.exit                  = vo_exit;
3156   this->vo.get_capabilities      = vo_get_capabilities;
3157   this->vo.enable_ovl            = vo_enable_overlay;
3158   this->vo.get_overlay_manager   = vo_get_overlay_manager;
3159   this->vo.flush                 = vo_flush;
3160   this->vo.trigger_drawing       = vo_trigger_drawing;
3161   this->vo.get_property          = vo_get_property;
3162   this->vo.set_property          = vo_set_property;
3163   this->vo.status                = vo_status;
3164   this->vo.driver                = driver;
3165 
3166   /* 24/25/30 fps are most common, do these in a single wait. */
3167   this->rp.poll_time             = 40000;
3168   this->rp.poll_limit            = 42000;
3169   this->rp.poll_num              = 200;
3170 
3171   /* default number of video frames from config */
3172   num_frame_buffers = xine->config->register_num (xine->config,
3173     "engine.buffers.video_num_frames",
3174     NUM_FRAME_BUFFERS, /* default */
3175     _("default number of video frames"),
3176     _("The default number of video frames to request "
3177       "from xine video out driver. Some drivers will "
3178       "override this setting with their own values."),
3179     20, NULL, NULL);
3180 
3181   /* check driver's limit and use the smaller value */
3182   {
3183     int i = driver->get_property (driver, VO_PROP_MAX_NUM_FRAMES);
3184     if (i && i < num_frame_buffers)
3185       num_frame_buffers = i;
3186   }
3187 
3188   /* we need at least 5 frames */
3189   if (num_frame_buffers<5)
3190     num_frame_buffers = 5;
3191 
3192   /* init frame usage stats */
3193   this->frames_total = num_frame_buffers;
3194 
3195   /* Choose a frame_drop_limit which matches num_frame_buffers.
3196    * xxmc for example supplies only 8 buffers. 2 are occupied by
3197    * MPEG2 decoding, further 2 for displaying and the remaining 4 can
3198    * hardly be filled all the time.
3199    * The below constants reserve buffers for decoding, displaying and
3200    * buffer fluctuation.
3201    * A frame_drop_limit_max below 1 will disable frame drops at all.
3202    */
3203   this->frame_drop_limit_max  = num_frame_buffers - 2 - 2 - 1;
3204   if (this->frame_drop_limit_max < 1)
3205     this->frame_drop_limit_max = 1;
3206   else if (this->frame_drop_limit_max > 3)
3207     this->frame_drop_limit_max = 3;
3208 
3209   this->frame_drop_limit      = this->frame_drop_limit_max;
3210 
3211   /* get some extra mem */
3212   {
3213     uint8_t *m = xine_mallocz_aligned (num_frame_buffers * (2 * sizeof (void *) + sizeof (extra_info_t)) + 32);
3214     if (!m) {
3215       free (this);
3216       return NULL;
3217     }
3218     this->display_queue.frames = (vo_frame_t **)m;
3219     m += num_frame_buffers * sizeof (void *);
3220     this->display_queue.img_streams = (xine_stream_private_t **)m;
3221     m += num_frame_buffers * sizeof (void *) + 31;
3222     m = (uint8_t *)((uintptr_t)m & ~(uintptr_t)31);
3223     this->extra_info_base = (extra_info_t *)m;
3224   }
3225 
3226   this->overlay_source = _x_video_overlay_new_manager (xine);
3227   if (this->overlay_source) {
3228     this->overlay_source->init (this->overlay_source);
3229     this->overlay_enabled = 1;
3230   }
3231 
3232   pthread_mutex_init (&this->trigger_drawing.mutex, NULL);
3233   pthread_cond_init (&this->trigger_drawing.wake, NULL);
3234   pthread_cond_init (&this->trigger_drawing.done_stepping, NULL);
3235 
3236   pthread_mutex_init (&this->driver_lock, NULL);
3237 
3238   pthread_mutex_init (&this->grab.lock, NULL);
3239   pthread_cond_init (&this->grab.wake, NULL);
3240 
3241   vo_streams_open (this);
3242 
3243   vo_free_queue_open (this);
3244   vo_display_queue_open (this);
3245   this->rp.ready_add = &this->rp.ready_first;
3246 
3247   /* nobody is listening yet, omit locking and signalling */
3248   {
3249     vo_frame_t **add = &this->free_queue.first;
3250     int i;
3251     for (i = 0; i < num_frame_buffers; i++) {
3252       vo_frame_t *img = driver->alloc_frame (driver);
3253       if (!img)
3254         break;
3255       img->proc_duplicate_frame_data = NULL;
3256       img->id   = i;
3257       img->port = &this->vo;
3258       img->free = vo_frame_dec_lock;
3259       img->lock = vo_frame_inc_lock;
3260       img->draw = vo_frame_draw;
3261       img->extra_info = &this->extra_info_base[i];
3262       this->display_queue.frames[i] = img;
3263       this->display_queue.img_streams[i] = NULL;
3264       *add = img;
3265       add = &img->next;
3266     }
3267     *add = NULL;
3268     this->free_queue.add = add;
3269     this->free_queue.num_buffers     =
3270     this->free_queue.num_buffers_max = i;
3271   }
3272 
3273   this->xine->port_ticket->revoke_cb_register (this->xine->port_ticket, vo_ticket_revoked, this);
3274 
3275   this->warn_skipped_threshold =
3276     xine->config->register_num (xine->config, "engine.performance.warn_skipped_threshold", 10,
3277     _("percentage of skipped frames to tolerate"),
3278     _("When more than this percentage of frames are not shown, because they "
3279       "were not decoded in time, xine sends a notification."),
3280     20, NULL, NULL);
3281   this->warn_discarded_threshold =
3282     xine->config->register_num (xine->config, "engine.performance.warn_discarded_threshold", 10,
3283     _("percentage of discarded frames to tolerate"),
3284     _("When more than this percentage of frames are not shown, because they "
3285       "were not scheduled for display in time, xine sends a notification."),
3286     20, NULL, NULL);
3287 
3288   if (grabonly) {
3289 
3290     this->grab_only = 1;
3291 
3292   } else {
3293 
3294     pthread_attr_t pth_attrs;
3295     int            err;
3296     /*
3297      * start video output thread
3298      *
3299      * this thread will alwys be running, displaying the
3300      * logo when "idle" thus making it possible to have
3301      * osd when not playing a stream
3302      */
3303 
3304     this->video_loop_running = 1;
3305 
3306     /* render thread needs no display queue signals */
3307     this->display_queue.locked_for_read = 1000;
3308 
3309     pthread_attr_init(&pth_attrs);
3310 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0)
3311     pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM);
3312 #endif
3313 
3314     err = pthread_create (&this->video_thread, &pth_attrs, video_out_loop, this);
3315     pthread_attr_destroy(&pth_attrs);
3316 
3317     if (err != 0) {
3318       xprintf (&this->xine->x, XINE_VERBOSITY_NONE, "video_out: can't create thread (%s)\n", strerror(err));
3319       /* FIXME: how does this happen ? */
3320       xprintf (&this->xine->x, XINE_VERBOSITY_LOG,
3321 	       _("video_out: sorry, this should not happen. please restart xine.\n"));
3322 
3323       this->video_loop_running = 0;
3324       this->vo.exit(&this->vo);
3325       return NULL;
3326     }
3327 
3328     this->clock->register_speed_change_callback (this->clock, vo_speed_change_cb, this);
3329     this->trigger_drawing.speed = this->clock->speed;
3330 
3331     xprintf (&this->xine->x, XINE_VERBOSITY_DEBUG, "video_out: thread created\n");
3332 
3333   }
3334 
3335   return &this->vo;
3336 }
3337