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