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 
21 /*
22  * top-level xine functions
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 #if defined (__linux__) || defined (__GLIBC__)
41 #include <endian.h>
42 #elif defined (__FreeBSD__)
43 #include <machine/endian.h>
44 #endif
45 
46 #ifdef HAVE_SETLOCALE
47 #include <locale.h>
48 #endif
49 
50 #include <basedir.h>
51 
52 #define LOG_MODULE "xine"
53 #define LOG_VERBOSE
54 /*
55 #define LOG
56 #define DEBUG
57 */
58 
59 #define XINE_ENABLE_EXPERIMENTAL_FEATURES
60 #define METRONOM_CLOCK_INTERNAL
61 #define POST_INTERNAL
62 
63 #include <xine/xine_internal.h>
64 #include <xine/plugin_catalog.h>
65 #include <xine/audio_out.h>
66 #include <xine/video_out.h>
67 #include <xine/post.h>
68 #include <xine/demux.h>
69 #include <xine/buffer.h>
70 #include <xine/spu_decoder.h>
71 #include <xine/input_plugin.h>
72 #include <xine/metronom.h>
73 #include <xine/configfile.h>
74 #include <xine/osd.h>
75 #include <xine/spu.h>
76 
77 #include <xine/xineutils.h>
78 #include <xine/compat.h>
79 
80 #ifdef WIN32
81 #   include <fcntl.h>
82 #   include <winsock.h>
83 #endif /* WIN32 */
84 
85 #include "xine_private.h"
86 
87 
88 
mutex_cleanup(void * mutex)89 static void mutex_cleanup (void *mutex) {
90   pthread_mutex_unlock ((pthread_mutex_t *) mutex);
91 }
92 
_x_handle_stream_end(xine_stream_t * s,int non_user)93 void _x_handle_stream_end (xine_stream_t *s, int non_user) {
94   xine_stream_private_t *stream = (xine_stream_private_t *)s;
95 
96   stream = stream->side_streams[0];
97   if (stream->status == XINE_STATUS_QUIT)
98     return;
99   stream->status = XINE_STATUS_STOP;
100 
101   if (non_user) {
102     /* frontends will not be interested in receiving this event
103      * if they have called xine_stop explicitly, so only send
104      * it if stream playback finished because of stream end reached
105      */
106 
107     xine_event_t event;
108 
109     stream->finished_naturally = 1;
110 
111     event.data_length = 0;
112     event.type        = XINE_EVENT_UI_PLAYBACK_FINISHED;
113 
114     xine_event_send (&stream->s, &event);
115   }
116 }
117 
_x_extra_info_reset(extra_info_t * extra_info)118 void _x_extra_info_reset( extra_info_t *extra_info ) {
119   memset( extra_info, 0, sizeof(extra_info_t) );
120 }
121 
_x_extra_info_merge(extra_info_t * dst,extra_info_t * src)122 void _x_extra_info_merge( extra_info_t *dst, extra_info_t *src ) {
123 
124   if (!src->invalid) {
125     if( src->input_normpos )
126       dst->input_normpos = src->input_normpos;
127 
128     if( src->input_time )
129       dst->input_time = src->input_time;
130 
131     if( src->frame_number )
132       dst->frame_number = src->frame_number;
133 
134     if( src->seek_count )
135       dst->seek_count = src->seek_count;
136 
137     if( src->vpts )
138       dst->vpts = src->vpts;
139   }
140 }
141 
xine_current_extra_info_reset(xine_stream_private_t * stream)142 static void xine_current_extra_info_reset (xine_stream_private_t *stream) {
143   int index = xine_refs_get (&stream->current_extra_info_index);
144   extra_info_t *b = &stream->current_extra_info[(index + 1) & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
145 
146   memset (b, 0, sizeof (*b));
147   xine_refs_add (&stream->current_extra_info_index, 1);
148 }
149 
xine_current_extra_info_set(xine_stream_private_t * stream,const extra_info_t * info)150 void xine_current_extra_info_set (xine_stream_private_t *stream, const extra_info_t *info) {
151   if (!info->invalid) {
152     int index = xine_refs_get (&stream->current_extra_info_index);
153     const extra_info_t *a = &stream->current_extra_info[index & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
154     extra_info_t *b = &stream->current_extra_info[(index + 1) & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
155 
156     b->input_normpos = info->input_normpos ? info->input_normpos : a->input_normpos;
157     b->input_time    = info->input_time    ? info->input_time    : a->input_time;
158     b->frame_number  = info->frame_number  ? info->frame_number  : a->frame_number;
159     b->seek_count    = info->seek_count    ? info->seek_count    : a->seek_count;
160     b->vpts          = info->vpts          ? info->vpts          : a->vpts;
161 
162     xine_refs_add (&stream->current_extra_info_index, 1);
163   }
164 }
165 
xine_current_extra_info_get(xine_stream_private_t * stream,extra_info_t * info)166 static int xine_current_extra_info_get (xine_stream_private_t *stream, extra_info_t *info) {
167   int index = xine_refs_get (&stream->current_extra_info_index);
168   const extra_info_t *a = &stream->current_extra_info[index & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
169 
170   *info = *a;
171   return stream->video_seek_count;
172 }
173 
174 #define XINE_TICKET_FLAG_PAUSE (int)0x40000000
175 
176 typedef struct {
177   xine_ticket_t   t;
178 
179   pthread_mutex_t lock;
180   pthread_cond_t  issued;
181   pthread_cond_t  revoked;
182   xine_rwlock_t   port_rewiring_lock;
183 
184   int             pause_revoked;
185   int             tickets_granted;
186   int             irrevocable_tickets;
187   int             plain_renewers;
188 
189   int             rewirers;
190   int             pending_revocations;
191   int             atomic_revokers;
192   pthread_t       atomic_revoker_thread;
193 
194   struct {
195     int count;
196     pthread_t holder;
197   } *holder_threads;
198   unsigned        holder_thread_count;
199 
200 #define XINE_TICKET_MAX_CB 15
201   xine_ticket_revoke_cb_t *revoke_callbacks[XINE_TICKET_MAX_CB + 1];
202   void *revoke_cb_data[XINE_TICKET_MAX_CB + 1];
203 } xine_ticket_private_t;
204 
ticket_revoke_cb_register(xine_ticket_t * tgen,xine_ticket_revoke_cb_t * cb,void * user_data)205 static void ticket_revoke_cb_register (xine_ticket_t *tgen, xine_ticket_revoke_cb_t *cb, void *user_data) {
206   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
207   int i;
208   pthread_mutex_lock (&this->lock);
209   for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
210     if (!this->revoke_callbacks[i]) {
211       this->revoke_callbacks[i] = cb;
212       this->revoke_cb_data[i]   = user_data;
213       break;
214     }
215     if ((this->revoke_callbacks[i] == cb) && (this->revoke_cb_data[i] == user_data))
216       break;
217   }
218   pthread_mutex_unlock (&this->lock);
219 }
220 
ticket_revoke_cb_unregister(xine_ticket_t * tgen,xine_ticket_revoke_cb_t * cb,void * user_data)221 static void ticket_revoke_cb_unregister (xine_ticket_t *tgen, xine_ticket_revoke_cb_t *cb, void *user_data) {
222   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
223   int f;
224   pthread_mutex_lock (&this->lock);
225   for (f = 0; this->revoke_callbacks[f]; f++) {
226     if ((this->revoke_callbacks[f] == cb) && (this->revoke_cb_data[f] == user_data)) {
227       int l;
228       for (l = f; this->revoke_callbacks[l + 1]; l++) ;
229       if (f < l) {
230         this->revoke_callbacks[f] = this->revoke_callbacks[l];
231         this->revoke_cb_data[f]   = this->revoke_cb_data[l];
232       }
233       this->revoke_callbacks[l] = NULL;
234       this->revoke_cb_data[l]   = NULL;
235       break;
236     }
237   }
238   pthread_mutex_unlock (&this->lock);
239 }
240 
ticket_acquire_internal(xine_ticket_private_t * this,int irrevocable,int nonblocking)241 static int ticket_acquire_internal (xine_ticket_private_t *this, int irrevocable, int nonblocking) {
242   pthread_t self = pthread_self ();
243   unsigned int wait, i;
244 
245   pthread_mutex_lock (&this->lock);
246 
247   /* find ourselves in user list */
248   for (i = 0; i < this->holder_thread_count; i++) {
249     if (pthread_equal (this->holder_threads[i].holder, self))
250       break;
251   }
252 
253   if (i >= this->holder_thread_count) {
254     /* not found */
255     wait = this->pending_revocations
256         && (this->atomic_revokers ? !pthread_equal (this->atomic_revoker_thread, self) : !irrevocable);
257     if (nonblocking && wait) {
258       /* not available immediately, bail out */
259       pthread_mutex_unlock (&this->lock);
260       return 0;
261     }
262     /* add */
263     if (((i & 31) == 31) && (this->holder_threads[i].count == -1000)) {
264       /* enlarge list */
265       void *new = realloc (this->holder_threads, sizeof (*this->holder_threads) * (i + 33));
266       if (!new) {
267         pthread_mutex_unlock (&this->lock);
268         return 0;
269       }
270       this->holder_threads = new;
271       this->holder_threads[i + 32].count = -1000;
272     }
273     this->holder_threads[i].count = 1;
274     this->holder_threads[i].holder = self;
275     this->holder_thread_count = i + 1;
276 
277     while (wait) {
278       pthread_cond_wait (&this->issued, &this->lock);
279       wait = this->pending_revocations
280         && (this->atomic_revokers ? !pthread_equal (this->atomic_revoker_thread, self) : !irrevocable);
281     }
282 
283   } else {
284     /* found, we already hold this */
285     this->holder_threads[i].count++;
286   }
287 
288   this->tickets_granted++;
289   if (irrevocable)
290     this->irrevocable_tickets++;
291 
292   pthread_mutex_unlock (&this->lock);
293   return 1;
294 }
295 
ticket_acquire_nonblocking(xine_ticket_t * tgen,int irrevocable)296 static int ticket_acquire_nonblocking(xine_ticket_t *tgen, int irrevocable) {
297   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
298   return ticket_acquire_internal(this, irrevocable, 1);
299 }
300 
ticket_acquire(xine_ticket_t * tgen,int irrevocable)301 static void ticket_acquire(xine_ticket_t *tgen, int irrevocable) {
302   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
303   ticket_acquire_internal(this, irrevocable, 0);
304 }
305 
ticket_release_internal(xine_ticket_private_t * this,int irrevocable)306 static void ticket_release_internal (xine_ticket_private_t *this, int irrevocable) {
307   pthread_t self = pthread_self ();
308   unsigned int i;
309 
310   pthread_mutex_lock (&this->lock);
311 
312   /* find ourselves in user list */
313   for (i = 0; i < this->holder_thread_count; i++) {
314     if (pthread_equal (this->holder_threads[i].holder, self))
315       break;
316   }
317 
318   if (i >= this->holder_thread_count) {
319     lprintf ("BUG! Ticket 0x%p released by a thread that never took it! Allowing code to continue\n", (void*)this);
320     _x_assert (0);
321   } else {
322     this->holder_threads[i].count--;
323     if (this->holder_threads[i].count == 0) {
324       this->holder_thread_count--;
325       if (i < this->holder_thread_count) {
326         this->holder_threads[i].count  = this->holder_threads[this->holder_thread_count].count;
327         this->holder_threads[i].holder = this->holder_threads[this->holder_thread_count].holder;
328       }
329     }
330   }
331 
332   if ((this->irrevocable_tickets > 0) && irrevocable)
333     this->irrevocable_tickets--;
334   if (this->tickets_granted > 0)
335     this->tickets_granted--;
336 
337   if (this->pending_revocations
338     && (!this->tickets_granted || (this->rewirers && !this->irrevocable_tickets)))
339     pthread_cond_broadcast(&this->revoked);
340 
341   pthread_mutex_unlock(&this->lock);
342 }
343 
ticket_release_nonblocking(xine_ticket_t * tgen,int irrevocable)344 static void ticket_release_nonblocking (xine_ticket_t *tgen, int irrevocable) {
345   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
346   ticket_release_internal (this, irrevocable);
347 }
348 
ticket_release(xine_ticket_t * tgen,int irrevocable)349 static void ticket_release (xine_ticket_t *tgen, int irrevocable) {
350   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
351   ticket_release_internal (this, irrevocable);
352 }
353 
ticket_renew(xine_ticket_t * tgen,int irrevocable)354 static void ticket_renew (xine_ticket_t *tgen, int irrevocable) {
355   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
356   unsigned int i;
357   int grants;
358   pthread_t self = pthread_self ();
359   pthread_mutex_lock (&this->lock);
360 #if 0
361   /* For performance, caller checks ticket_revoked without lock. 0 here is not really a bug. */
362   _x_assert (this->ticket_revoked);
363 #endif
364   do {
365     /* Never wait for self. This may happen when post plugins call this during their open (). */
366     if (this->atomic_revokers && pthread_equal (this->atomic_revoker_thread, self))
367         break;
368     /* Multithreaded decoders may well allocate frames outside the time window of the main
369      * decoding call. Usually, we cannot make those hidden threads acquire and release
370      * tickets properly. Blocking one of them may freeze main decoder with ticket held.
371      * Lets give them special treatment. */
372     for (i = 0; i < this->holder_thread_count; i++) {
373       if (pthread_equal (this->holder_threads[i].holder, self))
374         break;
375     }
376     if (i >= this->holder_thread_count) {
377       /* If registered threads are safe: Wait for ticket reissue,
378        * and dont burn cpu in endless retries.
379        * If registered threads are still running around: Fall through. */
380       while (this->pending_revocations && !this->tickets_granted)
381         pthread_cond_wait (&this->issued, &this->lock);
382       break;
383     }
384     /* If our thread still has saved self grants and calls this, restore them.
385       * Assume later reissue by another thread (engine pause). */
386     grants = this->holder_threads[i].count;
387     if (grants >= 0x80000) {
388       grants &= 0x7ffff;
389       this->holder_threads[i].count = grants;
390       this->tickets_granted += grants;
391     }
392     /* Lift _all_ our grants, avoid freeze when we have more than 1. */
393     if (irrevocable & XINE_TICKET_FLAG_REWIRE) {
394       /* allow everything */
395       this->tickets_granted -= grants;
396       if (!this->tickets_granted)
397         pthread_cond_broadcast (&this->revoked);
398       while (this->pending_revocations
399         && (!this->irrevocable_tickets || !(irrevocable & ~XINE_TICKET_FLAG_REWIRE)))
400         pthread_cond_wait (&this->issued, &this->lock);
401       this->tickets_granted += grants;
402     } else {
403       /* fair wheather (not rewire) mode */
404       this->plain_renewers++;
405       this->tickets_granted -= grants;
406       if (!this->tickets_granted)
407         pthread_cond_broadcast (&this->revoked);
408       while (this->pending_revocations
409         && (!this->irrevocable_tickets || !irrevocable)
410         && !this->rewirers)
411         pthread_cond_wait (&this->issued, &this->lock);
412       this->tickets_granted += grants;
413       this->plain_renewers--;
414     }
415   } while (0);
416   pthread_mutex_unlock (&this->lock);
417 }
418 
419 /* XINE_TICKET_FLAG_REWIRE implies XINE_TICKET_FLAG_ATOMIC. */
ticket_issue(xine_ticket_t * tgen,int flags)420 static void ticket_issue (xine_ticket_t *tgen, int flags) {
421   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
422   pthread_t self;
423   unsigned int i;
424 
425   /* better not miss a reissue, and skip that no lock test. */
426   self = pthread_self ();
427   pthread_mutex_lock (&this->lock);
428   if (flags == XINE_TICKET_FLAG_PAUSE) {
429     if (!this->pause_revoked) {
430       pthread_mutex_unlock (&this->lock);
431       return;
432     }
433     this->pause_revoked = 0;
434     flags = 0;
435   }
436 
437   if (this->pending_revocations > 0)
438     this->pending_revocations--;
439   if ((flags & XINE_TICKET_FLAG_REWIRE) && (this->rewirers > 0))
440     this->rewirers--;
441   if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC)) {
442     if (this->atomic_revokers > 0)
443       this->atomic_revokers--;
444     pthread_cond_broadcast (&this->revoked);
445   }
446 
447   {
448     int n = !this->pending_revocations ? 0 : (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
449     if (this->t.ticket_revoked != n) {
450       this->t.ticket_revoked = n;
451       pthread_cond_broadcast (&this->issued);
452     }
453   }
454 
455   /* HACK: restore self grants. */
456   for (i = 0; i < this->holder_thread_count; i++) {
457     if (pthread_equal (this->holder_threads[i].holder, self)) {
458       int n = this->holder_threads[i].count;
459       if (n >= 0x80000) {
460         n -= 0x80000;
461         this->holder_threads[i].count = n;
462         if (n < 0x80000)
463           this->tickets_granted += n;
464       }
465       break;
466     }
467   }
468 
469   pthread_mutex_unlock(&this->lock);
470   if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
471     xine_rwlock_unlock (&this->port_rewiring_lock);
472 }
473 
ticket_revoke(xine_ticket_t * tgen,int flags)474 static void ticket_revoke (xine_ticket_t *tgen, int flags) {
475   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
476   pthread_t self;
477 
478   if (flags == XINE_TICKET_FLAG_PAUSE) {
479     if (this->pause_revoked)
480       return;
481     self = pthread_self ();
482     /* flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC) does not happen here. */
483     pthread_mutex_lock (&this->lock);
484     if (this->pause_revoked) {
485       pthread_mutex_unlock (&this->lock);
486       return;
487     }
488     this->pause_revoked = 1;
489     flags = 0;
490   } else {
491     self = pthread_self ();
492     if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
493       xine_rwlock_wrlock (&this->port_rewiring_lock);
494     pthread_mutex_lock (&this->lock);
495   }
496 
497   /* HACK: dont freeze on self grants, save them.
498    * Also, nest revokes at bit 19. */
499   {
500     unsigned int i;
501     for (i = 0; i < this->holder_thread_count; i++) {
502       if (pthread_equal (this->holder_threads[i].holder, self)) {
503         int n = this->holder_threads[i].count;
504         if (n < 0x80000)
505           this->tickets_granted -= n;
506         this->holder_threads[i].count = n + 0x80000;
507         break;
508       }
509     }
510   }
511 
512   /* Set these early so release () / renew () see them. */
513   this->pending_revocations++;
514 
515   /* No joke - see renew (). */
516   if (flags & XINE_TICKET_FLAG_REWIRE) {
517     this->rewirers++;
518     if (this->plain_renewers)
519       pthread_cond_broadcast (&this->issued);
520   }
521 
522   /* New public status. */
523   this->t.ticket_revoked = (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
524 
525   do {
526     /* Never wait for self. */
527     if (this->atomic_revokers && pthread_equal (this->atomic_revoker_thread, self)) {
528       if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
529         this->atomic_revokers++;
530       break;
531     }
532     /* Need waiting? */
533     if (this->tickets_granted || (this->rewirers && this->plain_renewers) || this->atomic_revokers) {
534       /* Notify other holders. */
535       int i, f = (this->rewirers ? XINE_TICKET_FLAG_REWIRE : 0)
536                | (this->atomic_revokers ? XINE_TICKET_FLAG_ATOMIC : 0);
537       for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
538         if (!this->revoke_callbacks[i])
539           break;
540         this->revoke_callbacks[i] (this->revoke_cb_data[i], f);
541       }
542       /* Wait for them to release/renew. */
543       do {
544         pthread_cond_wait (&this->revoked, &this->lock);
545         this->t.ticket_revoked = (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
546       } while (this->tickets_granted || (this->rewirers && this->plain_renewers) || this->atomic_revokers);
547     }
548     /* Its ours now. */
549     if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC)) {
550       this->atomic_revoker_thread = self;
551       this->atomic_revokers++;
552     }
553   } while (0);
554 
555   pthread_mutex_unlock(&this->lock);
556 }
557 
lock_timeout(pthread_mutex_t * mutex,int ms_timeout)558 static int lock_timeout (pthread_mutex_t *mutex, int ms_timeout) {
559   if (ms_timeout == 0)
560     return (0 == pthread_mutex_trylock (mutex));
561   if (ms_timeout >= 0) {
562     struct timespec abstime = {0, 0};
563     xine_gettime (&abstime);
564     abstime.tv_sec  +=  ms_timeout / 1000;
565     abstime.tv_nsec += (ms_timeout % 1000) * 1000000;
566     if (abstime.tv_nsec >= 1000000000) {
567       abstime.tv_nsec -= 1000000000;
568       abstime.tv_sec++;
569     }
570     return (0 == pthread_mutex_timedlock (mutex, &abstime));
571   }
572   pthread_mutex_lock (mutex);
573   return 1;
574 }
575 
ticket_lock_port_rewiring(xine_ticket_t * tgen,int ms_timeout)576 static int ticket_lock_port_rewiring (xine_ticket_t *tgen, int ms_timeout) {
577   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
578   if (ms_timeout == 0)
579     return (0 == xine_rwlock_tryrdlock (&this->port_rewiring_lock));
580   if (ms_timeout >= 0) {
581     struct timespec abstime = {0, 0};
582     xine_gettime (&abstime);
583     abstime.tv_sec  +=  ms_timeout / 1000;
584     abstime.tv_nsec += (ms_timeout % 1000) * 1000000;
585     if (abstime.tv_nsec >= 1000000000) {
586       abstime.tv_nsec -= 1000000000;
587       abstime.tv_sec++;
588     }
589     return (0 == xine_rwlock_timedrdlock (&this->port_rewiring_lock, &abstime));
590   }
591   xine_rwlock_rdlock (&this->port_rewiring_lock);
592   return 1;
593 }
594 
ticket_unlock_port_rewiring(xine_ticket_t * tgen)595 static void ticket_unlock_port_rewiring (xine_ticket_t *tgen) {
596   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
597   xine_rwlock_unlock (&this->port_rewiring_lock);
598 }
599 
ticket_dispose(xine_ticket_t * tgen)600 static void ticket_dispose (xine_ticket_t *tgen) {
601   xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
602 
603   xine_rwlock_destroy   (&this->port_rewiring_lock);
604   pthread_mutex_destroy (&this->lock);
605   pthread_cond_destroy  (&this->issued);
606   pthread_cond_destroy  (&this->revoked);
607 
608   free (this->holder_threads);
609   free (this);
610 }
611 
ticket_init(void)612 static xine_ticket_t *XINE_MALLOC ticket_init(void) {
613   xine_ticket_private_t *port_ticket;
614 
615   port_ticket = calloc (1, sizeof (xine_ticket_private_t));
616   if (!port_ticket)
617     return NULL;
618 #ifndef HAVE_ZERO_SAFE_MEM
619   port_ticket->t.ticket_revoked     = 0;
620   port_ticket->pause_revoked        = 0;
621   port_ticket->holder_thread_count  = 0;
622   port_ticket->tickets_granted      = 0;
623   port_ticket->irrevocable_tickets  = 0;
624   port_ticket->atomic_revokers      = 0;
625   port_ticket->rewirers             = 0;
626   port_ticket->plain_renewers       = 0;
627   {
628     int i;
629     for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
630       port_ticket->revoke_callbacks[i] = NULL;
631       port_ticket->revoke_cb_data[i]   = NULL;
632     }
633   }
634 #endif
635   port_ticket->t.acquire_nonblocking  = ticket_acquire_nonblocking;
636   port_ticket->t.acquire              = ticket_acquire;
637   port_ticket->t.release_nonblocking  = ticket_release_nonblocking;
638   port_ticket->t.release              = ticket_release;
639   port_ticket->t.renew                = ticket_renew;
640   port_ticket->t.revoke_cb_register   = ticket_revoke_cb_register;
641   port_ticket->t.revoke_cb_unregister = ticket_revoke_cb_unregister;
642   port_ticket->t.issue                = ticket_issue;
643   port_ticket->t.revoke               = ticket_revoke;
644   port_ticket->t.lock_port_rewiring   = ticket_lock_port_rewiring;
645   port_ticket->t.unlock_port_rewiring = ticket_unlock_port_rewiring;
646   port_ticket->t.dispose              = ticket_dispose;
647   port_ticket->holder_threads         = malloc (32 * sizeof (*port_ticket->holder_threads));
648   if (!port_ticket->holder_threads) {
649     free (port_ticket);
650     return NULL;
651   }
652   port_ticket->holder_threads[31].count = -1000;
653 
654   pthread_mutex_init       (&port_ticket->lock, NULL);
655   xine_rwlock_init_default (&port_ticket->port_rewiring_lock);
656   pthread_cond_init        (&port_ticket->issued, NULL);
657   pthread_cond_init        (&port_ticket->revoked, NULL);
658 
659   return &port_ticket->t;
660 }
661 
set_speed_internal(xine_stream_private_t * stream,int speed)662 static void set_speed_internal (xine_stream_private_t *stream, int speed) {
663   xine_private_t *xine = (xine_private_t *)stream->s.xine;
664   int old_speed = xine->x.clock->speed;
665   int mode = 2 * (speed == XINE_SPEED_PAUSE) + (old_speed == XINE_SPEED_PAUSE);
666 
667   if (mode & 1) {
668     if (mode & 2) {
669       /* stay paused */
670       return;
671     } else {
672       /* switch pause mode */
673       if (speed == XINE_LIVE_PAUSE_ON) {
674         xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
675         return;
676       }
677       if (speed == XINE_LIVE_PAUSE_OFF) {
678         xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
679         return;
680       }
681       /* unpause. all decoder and post threads may continue now, if not running already. */
682       xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
683     }
684   } else {
685     if (mode & 2) {
686       /* pause */
687       /* get all decoder and post threads in a state where they agree to be blocked */
688       xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
689       /* set master clock so audio_out loop can pause in a safe place */
690       xine->x.clock->set_fine_speed (xine->x.clock, speed);
691     } else {
692       if ((speed == XINE_LIVE_PAUSE_ON) || (speed == XINE_LIVE_PAUSE_OFF))
693         return;
694       /* plain change */
695       if (speed == old_speed)
696         return;
697     }
698   }
699 
700   /* see coment on audio_out loop about audio_paused */
701   if (stream->s.audio_out) {
702     xine->port_ticket->acquire (xine->port_ticket, 1);
703 
704     /* inform audio_out that speed has changed - he knows what to do */
705     stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_CLOCK_SPEED, speed);
706 
707     xine->port_ticket->release (xine->port_ticket, 1);
708   }
709 
710   if (mode < 2)
711     /* master clock is set after resuming the audio device (audio_out loop may continue) */
712     xine->x.clock->set_fine_speed (xine->x.clock, speed);
713 }
714 
715 
716 /* SPEED_FLAG_IGNORE_CHANGE must be set in stream->speed_change_flags, when entering this function */
stop_internal(xine_stream_private_t * stream)717 static void stop_internal (xine_stream_private_t *stream) {
718   lprintf ("status before = %d\n", stream->status);
719 
720   if (stream->side_streams[0] == stream)
721     stream->demux.start_buffers_sent = 0;
722   stream = stream->side_streams[0];
723 
724   if ( stream->status == XINE_STATUS_IDLE ||
725        stream->status == XINE_STATUS_STOP ) {
726     _x_demux_control_end (&stream->s, 0);
727     lprintf("ignored");
728   } else {
729     /* make sure we're not in "paused" state */
730     set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
731 
732     /* Don't change status if we're quitting */
733     if (stream->status != XINE_STATUS_QUIT)
734       stream->status = XINE_STATUS_STOP;
735   }
736   /*
737    * stop demux
738    */
739   {
740     unsigned int u;
741     for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
742       xine_stream_private_t *side = stream->side_streams[u];
743       if (side && side->demux.plugin && side->demux.thread_created) {
744         lprintf ("stopping demux\n");
745         _x_demux_stop_thread (&side->s);
746         lprintf ("demux stopped\n");
747       }
748     }
749   }
750   lprintf ("done\n");
751 }
752 
753 /* force engine to run at normal speed. if you are about to grab a ticket,
754  * do wait for the rare case of a set_fine_speed (0) in progress. */
755 
lock_run(xine_stream_private_t * stream,int wait)756 static void lock_run (xine_stream_private_t *stream, int wait) {
757   xine_private_t *xine = (xine_private_t *)stream->s.xine;
758 
759   pthread_mutex_lock (&xine->speed_change_lock);
760   if (xine->speed_change_flags & SPEED_FLAG_CHANGING) {
761     xine->speed_change_flags |= SPEED_FLAG_IGNORE_CHANGE | SPEED_FLAG_WANT_NEW;
762     xine->speed_change_new_speed = XINE_FINE_SPEED_NORMAL;
763     if (wait) {
764       do {
765         pthread_cond_wait (&xine->speed_change_done, &xine->speed_change_lock);
766       } while (xine->speed_change_flags & SPEED_FLAG_CHANGING);
767     }
768     pthread_mutex_unlock (&xine->speed_change_lock);
769     return;
770   }
771   xine->speed_change_flags |= SPEED_FLAG_IGNORE_CHANGE;
772   pthread_mutex_unlock (&xine->speed_change_lock);
773 
774   if (xine->x.clock->speed == XINE_FINE_SPEED_NORMAL)
775     return;
776   xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "set_speed %d.\n", XINE_FINE_SPEED_NORMAL);
777   set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
778 }
779 
unlock_run(xine_stream_private_t * stream)780 static void unlock_run (xine_stream_private_t *stream) {
781   xine_private_t *xine = (xine_private_t *)stream->s.xine;
782 
783   pthread_mutex_lock (&xine->speed_change_lock);
784   xine->speed_change_flags &= ~SPEED_FLAG_IGNORE_CHANGE;
785   pthread_mutex_unlock (&xine->speed_change_lock);
786 }
787 
xine_stop(xine_stream_t * s)788 void xine_stop (xine_stream_t *s) {
789   xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
790   xine_private_t *xine;
791 
792   if (!stream)
793     return;
794   m = stream->side_streams[0];
795   xine = (xine_private_t *)m->s.xine;
796 
797   pthread_mutex_lock (&m->frontend_lock);
798   pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
799 
800   /* make sure that other threads cannot change the speed, especially pauseing the stream */
801   lock_run (m, 1);
802 
803   xine->port_ticket->acquire (xine->port_ticket, 1);
804 
805   if (m->s.audio_out)
806     m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
807   if (m->s.video_out)
808     m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
809 
810   stop_internal (m);
811 
812   if (m->s.slave && (m->slave_affection & XINE_MASTER_SLAVE_STOP))
813     xine_stop (m->s.slave);
814 
815   if (m->s.video_out)
816     m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
817   if (m->s.audio_out)
818     m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
819 
820   xine->port_ticket->release (xine->port_ticket, 1);
821   unlock_run (m);
822 
823   pthread_cleanup_pop (0);
824   pthread_mutex_unlock (&m->frontend_lock);
825 }
826 
827 
close_internal(xine_stream_private_t * stream)828 static void close_internal (xine_stream_private_t *stream) {
829   xine_stream_private_t *m = stream->side_streams[0];
830   xine_private_t *xine = (xine_private_t *)m->s.xine;
831   int flush = !m->gapless_switch && !m->finished_naturally;
832 
833   if (m->s.slave) {
834     xine_close (m->s.slave);
835     if (m->slave_is_subtitle) {
836       xine_dispose (m->s.slave);
837       m->s.slave = NULL;
838       m->slave_is_subtitle = 0;
839     }
840   }
841 
842   /* make sure that other threads cannot change the speed.
843    * especially pauseing the stream may hold demux waiting for fifo pool or ticket,
844    * and thus freeze stop_internal () -> _x_demux_stop_thread () below. */
845   lock_run (m, flush);
846 
847   if (flush) {
848     xine->port_ticket->acquire (xine->port_ticket, 1);
849 
850     if (m->s.audio_out)
851       m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
852     if (m->s.video_out)
853       m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
854   }
855 
856   stop_internal (stream);
857 
858   if (flush) {
859     if (m->s.video_out)
860       m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
861     if (m->s.audio_out)
862       m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
863 
864     xine->port_ticket->release (xine->port_ticket, 1);
865   }
866 
867   unlock_run (m);
868 
869   if (stream == m) {
870     unsigned int u;
871     for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
872       xine_stream_private_t *side = stream->side_streams[u];
873       if (side) {
874         if (side->demux.plugin)
875           _x_free_demux_plugin (&side->s, &side->demux.plugin);
876         if (side->s.input_plugin) {
877           _x_free_input_plugin (&side->s, side->s.input_plugin);
878           side->s.input_plugin = NULL;
879         }
880       }
881     }
882   } else {
883     if (stream->demux.plugin)
884       _x_free_demux_plugin (&stream->s, &stream->demux.plugin);
885     if (stream->s.input_plugin) {
886       _x_free_input_plugin (&stream->s, stream->s.input_plugin);
887       stream->s.input_plugin = NULL;
888     }
889   }
890 
891   /*
892    * reset / free meta info
893    * XINE_STREAM_INFO_MAX is at least 99 but the info arrays are sparsely used.
894    * Save a lot of mutex/free calls.
895    */
896   if (stream == m) {
897     int i;
898     xine_rwlock_wrlock (&stream->info_lock);
899     for (i = 0; i < XINE_STREAM_INFO_MAX; i++)
900       stream->stream_info[i] = 0;
901     xine_rwlock_unlock (&stream->info_lock);
902     xine_rwlock_wrlock (&stream->meta_lock);
903     for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
904       if (stream->meta_info_public[i]) {
905         if (stream->meta_info_public[i] != stream->meta_info[i])
906           free (stream->meta_info_public[i]);
907         stream->meta_info_public[i] = NULL;
908       }
909       if (stream->meta_info[i])
910         free (stream->meta_info[i]), stream->meta_info[i] = NULL;
911     }
912     xine_rwlock_unlock (&stream->meta_lock);
913   }
914   stream->audio_track_map_entries = 0;
915   stream->spu_track_map_entries = 0;
916 
917   _x_keyframes_set (&stream->s, NULL, 0);
918 }
919 
xine_close(xine_stream_t * s)920 void xine_close (xine_stream_t *s) {
921   xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
922   /* a function that uses pthread_cleanup_push () should not modify its
923    * arguments. it also should not modify a variable that optimizes to
924    * be the same as an arg ("stream"). this avoids a "may be clobbered
925    * by longjmp () or vfork () warning. */
926 
927   /* phonon bug */
928   if (!stream) {
929     printf ("xine_close: BUG: stream = NULL.\n");
930     return;
931   }
932 
933   m = stream->side_streams[0];
934   pthread_mutex_lock (&m->frontend_lock);
935   pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
936 
937   close_internal (m);
938 
939   /*
940    * set status to idle.
941    * not putting this into close_internal because it is also called
942    * by open_internal.
943    */
944 
945   /* Don't change status if we're quitting */
946   if (m->status != XINE_STATUS_QUIT)
947     m->status = XINE_STATUS_IDLE;
948 
949   pthread_cleanup_pop (0);
950   pthread_mutex_unlock (&m->frontend_lock);
951 }
952 
stream_rewire_audio(xine_post_out_t * output,void * data)953 static int stream_rewire_audio(xine_post_out_t *output, void *data)
954 {
955   xine_stream_private_t *stream = (xine_stream_private_t *)output->data;
956   xine_private_t *xine = (xine_private_t *)stream->s.xine;
957   xine_audio_port_t *new_port = (xine_audio_port_t *)data, *old_port;
958   uint32_t bits, rate;
959   int mode;
960 
961   if (!data)
962     return 0;
963 
964   stream = stream->side_streams[0];
965 
966   xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
967   /* just an optimization. Keep engine paused at rewire safe position for subsequent rewires. */
968   set_speed_internal (stream, XINE_LIVE_PAUSE_OFF);
969 
970   old_port = stream->s.audio_out;
971   _x_post_audio_port_ref (new_port);
972   if (old_port->status (old_port, &stream->s, &bits, &rate, &mode)) {
973     /* register our stream at the new output port */
974     (new_port->open) (new_port, &stream->s, bits, rate, mode);
975     old_port->close (old_port, &stream->s);
976   }
977   stream->s.audio_out = new_port;
978   _x_post_audio_port_unref (old_port);
979 
980   xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
981 
982   return 1;
983 }
984 
stream_rewire_video(xine_post_out_t * output,void * data)985 static int stream_rewire_video(xine_post_out_t *output, void *data)
986 {
987   xine_stream_private_t *stream = (xine_stream_private_t *)output->data;
988   xine_private_t *xine = (xine_private_t *)stream->s.xine;
989   xine_video_port_t *new_port = (xine_video_port_t *)data, *old_port;
990   int64_t img_duration;
991   int width, height;
992 
993   if (!data)
994     return 0;
995 
996   stream = stream->side_streams[0];
997 
998   xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
999   /* just an optimization. Keep engine paused at rewire safe position for subsequent rewires. */
1000   set_speed_internal (stream, XINE_LIVE_PAUSE_OFF);
1001 
1002   old_port = stream->s.video_out;
1003   _x_post_video_port_ref (new_port);
1004   if (old_port->status (old_port, &stream->s, &width, &height, &img_duration)) {
1005     /* register our stream at the new output port */
1006     (new_port->open) (new_port, &stream->s);
1007     old_port->close (old_port, &stream->s);
1008   }
1009   stream->s.video_out = new_port;
1010   _x_post_video_port_unref (old_port);
1011 
1012   xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
1013 
1014   return 1;
1015 }
1016 
video_decoder_update_disable_flush_at_discontinuity(void * s,xine_cfg_entry_t * entry)1017 static void video_decoder_update_disable_flush_at_discontinuity (void *s, xine_cfg_entry_t *entry) {
1018   xine_stream_private_t *stream = (xine_stream_private_t *)s;
1019   stream = stream->side_streams[0];
1020   stream->disable_decoder_flush_at_discontinuity = !!entry->num_value;
1021 }
1022 
_xine_dummy_dest(void * object)1023 static void _xine_dummy_dest (void *object) {
1024   (void)object;
1025 }
1026 
1027 static void xine_dispose_internal (xine_stream_private_t *stream);
1028 
xine_stream_new(xine_t * this,xine_audio_port_t * ao,xine_video_port_t * vo)1029 xine_stream_t *xine_stream_new (xine_t *this, xine_audio_port_t *ao, xine_video_port_t *vo) {
1030 
1031   xine_stream_private_t *stream;
1032   pthread_mutexattr_t attr;
1033 
1034   xprintf (this, XINE_VERBOSITY_DEBUG, "xine_stream_new\n");
1035 
1036   /* create a new stream object */
1037   stream = calloc (1, sizeof (*stream));
1038   if (!stream)
1039     goto err_null;
1040 #ifndef HAVE_ZERO_SAFE_MEM
1041   /* Do these first, when compiler still knows stream is all zeroed.
1042    * Let it optimize away this on most systems where clear mem
1043    * interpretes as 0, 0f or NULL safely.
1044    */
1045   stream->s.spu_decoder_plugin     = NULL;
1046   stream->audio_decoder_plugin     = NULL;
1047   stream->early_finish_event       = 0;
1048   stream->delay_finish_event       = 0;
1049   stream->gapless_switch           = 0;
1050   stream->keep_ao_driver_open      = 0;
1051   stream->video_channel            = 0;
1052   stream->video_decoder_plugin     = NULL;
1053   stream->counter.headers_audio    = 0;
1054   stream->counter.headers_video    = 0;
1055   stream->counter.finisheds_audio  = 0;
1056   stream->counter.finisheds_video  = 0;
1057   stream->counter.demuxers_running = 0;
1058   stream->counter.nbc_refs         = 0;
1059   stream->counter.nbc              = NULL;
1060   stream->demux.action_pending     = 0;
1061   stream->demux.input_caps         = 0;
1062   stream->demux.thread_created     = 0;
1063   stream->demux.thread_running     = 0;
1064   stream->demux.start_buffers_sent = 0;
1065   stream->err                      = 0;
1066   stream->broadcaster              = NULL;
1067   stream->index.array              = NULL;
1068   stream->s.slave                  = NULL;
1069   stream->slave_is_subtitle        = 0;
1070   stream->query_input_plugins[0]   = NULL;
1071   stream->query_input_plugins[1]   = NULL;
1072   {
1073     int i;
1074     for (i = 1; i < XINE_NUM_SIDE_STREAMS; i++)
1075       stream->side_streams[i] = NULL;
1076     for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
1077       stream->stream_info[i] = 0;
1078       stream->meta_info_public[i]   = stream->meta_info[i]   = NULL;
1079     }
1080   }
1081 #endif
1082   /* no need to memset again
1083   _x_extra_info_reset (&stream->ei[0]);
1084   _x_extra_info_reset (&stream->ei[1]);
1085   */
1086 
1087   stream->audio_decoder_extra_info = &stream->ei[0];
1088   stream->video_decoder_extra_info = &stream->ei[1];
1089 
1090   stream->side_streams[0]       = stream;
1091   stream->id_flag               = 1 << 0;
1092   stream->s.xine                = this;
1093   stream->status                = XINE_STATUS_IDLE;
1094 
1095   stream->video_source.name   = "video source";
1096   stream->video_source.type   = XINE_POST_DATA_VIDEO;
1097   stream->video_source.data   = &stream->s;
1098   stream->video_source.rewire = stream_rewire_video;
1099 
1100   stream->audio_source.name   = "audio source";
1101   stream->audio_source.type   = XINE_POST_DATA_AUDIO;
1102   stream->audio_source.data   = &stream->s;
1103   stream->audio_source.rewire = stream_rewire_audio;
1104 
1105   stream->demux.max_seek_bufs        = 0xffffffff;
1106   stream->s.spu_decoder_streamtype   = -1;
1107   stream->s.audio_out                = ao;
1108   stream->audio_channel_user         = -1;
1109   stream->s.audio_channel_auto       = -1;
1110   stream->audio_decoder_streamtype   = -1;
1111   stream->s.spu_channel_auto         = -1;
1112   stream->s.spu_channel_letterbox    = -1;
1113   stream->spu_channel_pan_scan       = -1;
1114   stream->s.spu_channel_user         = -1;
1115   stream->s.spu_channel              = -1;
1116   /* Do not flush output when opening/closing yet unused streams (eg subtitle). */
1117   stream->finished_naturally         = 1;
1118   stream->s.video_out                = vo;
1119   stream->s.video_driver             = vo ? vo->driver : NULL;
1120   stream->video_decoder_streamtype   = -1;
1121   /* initial master/slave */
1122   stream->s.master                   = &stream->s;
1123 
1124   /* event queues */
1125   stream->event.queues = xine_list_new ();
1126   if (!stream->event.queues)
1127     goto err_free;
1128 
1129   /* init mutexes and conditions */
1130   xine_refs_init (&stream->current_extra_info_index, _xine_dummy_dest, stream);
1131   xine_rwlock_init_default (&stream->info_lock);
1132   xine_rwlock_init_default (&stream->meta_lock);
1133   pthread_mutex_init (&stream->demux.lock, NULL);
1134   pthread_mutex_init (&stream->demux.action_lock, NULL);
1135   pthread_mutex_init (&stream->demux.pair, NULL);
1136   pthread_cond_init  (&stream->demux.resume, NULL);
1137   pthread_mutex_init (&stream->event.lock, NULL);
1138   pthread_mutex_init (&stream->counter.lock, NULL);
1139   pthread_cond_init  (&stream->counter.changed, NULL);
1140   pthread_mutex_init (&stream->first_frame.lock, NULL);
1141   pthread_cond_init  (&stream->first_frame.reached, NULL);
1142   pthread_mutex_init (&stream->index.lock, NULL);
1143 
1144   /* warning: frontend_lock is a recursive mutex. it must NOT be
1145    * used with neither pthread_cond_wait() or pthread_cond_timedwait()
1146    */
1147   pthread_mutexattr_init(&attr);
1148   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1149   pthread_mutex_init (&stream->frontend_lock, &attr);
1150   pthread_mutexattr_destroy(&attr);
1151 
1152   pthread_mutex_lock (&this->streams_lock);
1153 
1154   /* some user config */
1155   stream->disable_decoder_flush_at_discontinuity = this->config->register_bool (this->config,
1156     "engine.decoder.disable_flush_at_discontinuity", 0,
1157     _("disable decoder flush at discontinuity"),
1158     _("when watching live tv a discontinuity happens for example about every 26.5 hours due to a pts wrap.\n"
1159       "flushing the decoder at that time causes decoding errors for images after the pts wrap.\n"
1160       "to avoid the decoding errors, decoder flush at discontinuity should be disabled.\n\n"
1161       "WARNING: as the flush was introduced to fix some issues when playing DVD still images, it is\n"
1162       "likely that these issues may reappear in case they haven't been fixed differently meanwhile.\n"),
1163     20, video_decoder_update_disable_flush_at_discontinuity, stream);
1164 
1165   /* create a metronom */
1166   stream->s.metronom = _x_metronom_init ( (vo != NULL), (ao != NULL), this);
1167   if (!stream->s.metronom)
1168     goto err_mutex;
1169 
1170   /* alloc fifos, init and start decoder threads */
1171   if (!_x_video_decoder_init (&stream->s))
1172     goto err_metronom;
1173 
1174   if (!_x_audio_decoder_init (&stream->s))
1175     goto err_video;
1176 
1177   /* osd */
1178   if (vo) {
1179     _x_spu_misc_init (this);
1180     stream->s.osd_renderer = _x_osd_renderer_init (&stream->s);
1181   } else
1182     stream->s.osd_renderer = NULL;
1183 
1184   /* create a reference counter */
1185   xine_refs_init (&stream->refs, (void (*)(void *))xine_dispose_internal, &stream->s);
1186 
1187   /* register stream */
1188   xine_list_push_back (this->streams, &stream->s);
1189   pthread_mutex_unlock (&this->streams_lock);
1190   return &stream->s;
1191 
1192   /* err_audio: */
1193   /* _x_audio_decoder_shutdown (&stream->s); */
1194 
1195   err_video:
1196   _x_video_decoder_shutdown (&stream->s);
1197 
1198   err_metronom:
1199   stream->s.metronom->exit (stream->s.metronom);
1200 
1201   err_mutex:
1202   pthread_mutex_unlock  (&this->streams_lock);
1203   pthread_mutex_destroy (&stream->frontend_lock);
1204   pthread_mutex_destroy (&stream->index.lock);
1205   pthread_cond_destroy  (&stream->first_frame.reached);
1206   pthread_mutex_destroy (&stream->first_frame.lock);
1207   pthread_cond_destroy  (&stream->counter.changed);
1208   pthread_mutex_destroy (&stream->counter.lock);
1209   pthread_mutex_destroy (&stream->event.lock);
1210   pthread_cond_destroy  (&stream->demux.resume);
1211   pthread_mutex_destroy (&stream->demux.pair);
1212   pthread_mutex_destroy (&stream->demux.action_lock);
1213   pthread_mutex_destroy (&stream->demux.lock);
1214   xine_rwlock_destroy   (&stream->meta_lock);
1215   xine_rwlock_destroy   (&stream->info_lock);
1216   xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
1217   xine_list_delete      (stream->event.queues);
1218 
1219   err_free:
1220   free (stream);
1221 
1222   err_null:
1223   return NULL;
1224 }
1225 
xine_side_dispose_internal(xine_stream_private_t * stream)1226 static void xine_side_dispose_internal (xine_stream_private_t *stream) {
1227   xine_t *xine = stream->s.xine;
1228 
1229   lprintf ("stream: %p\n", (void*)stream);
1230 
1231   xine->config->unregister_callbacks (xine->config, NULL, NULL, stream, sizeof (*stream));
1232 
1233   {
1234     xine_stream_private_t *m = stream->side_streams[0];
1235     unsigned int u;
1236     xine_rwlock_wrlock (&m->info_lock);
1237     for (u = 1; u < XINE_NUM_SIDE_STREAMS; u++) {
1238       if (m->side_streams[u] == stream) {
1239         m->side_streams[u] = NULL;
1240         break;
1241       }
1242     }
1243     xine_rwlock_unlock (&m->info_lock);
1244     if (u < XINE_NUM_SIDE_STREAMS)
1245       xine_refs_sub (&m->refs, 1);
1246   }
1247 
1248   /* these are not used in side streams.
1249   xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
1250   pthread_mutex_destroy (&stream->frontend_lock);
1251   pthread_mutex_destroy (&stream->index.lock);
1252   pthread_mutex_destroy (&stream->demux.pair_mutex);
1253   pthread_mutex_destroy (&stream->event.lock);
1254   pthread_mutex_destroy (&stream->counter.lock);
1255   pthread_mutex_destroy (&stream->first_frame.lock);
1256   pthread_cond_destroy  (&stream->first_frame.reached);
1257   pthread_cond_destroy  (&stream->counter.changed);
1258   xine_rwlock_destroy   (&stream->meta_lock);
1259   xine_rwlock_destroy   (&stream->info_lock);
1260   */
1261   pthread_cond_destroy  (&stream->demux.resume);
1262   pthread_mutex_destroy (&stream->demux.action_lock);
1263   pthread_mutex_destroy (&stream->demux.lock);
1264 
1265   free (stream->index.array);
1266   free (stream);
1267 }
1268 
xine_get_side_stream(xine_stream_t * master,int index)1269 xine_stream_t *xine_get_side_stream (xine_stream_t *master, int index) {
1270   xine_stream_private_t *m = (xine_stream_private_t *)master, *s;
1271 
1272   if (!m || (index < 0) || (index >= XINE_NUM_SIDE_STREAMS))
1273     return NULL;
1274   /* no sub-sides, please. */
1275   m = m->side_streams[0];
1276   xine_rwlock_rdlock (&m->info_lock);
1277   s = m->side_streams[index];
1278   xine_rwlock_unlock (&m->info_lock);
1279   if (s)
1280     return &s->s;
1281 
1282   xprintf (m->s.xine, XINE_VERBOSITY_DEBUG, "xine_side_stream_new (%p, %d)\n", (void *)m, index);
1283 
1284   /* create a new stream object */
1285   s = calloc (1, sizeof (*s));
1286   if (!s)
1287     return NULL;
1288 
1289 #ifndef HAVE_ZERO_SAFE_MEM
1290   s->s.spu_decoder_plugin     = NULL;
1291   s->audio_decoder_plugin     = NULL;
1292   s->audio_track_map_entries  = 0;
1293   s->audio_type               = 0;
1294   s->early_finish_event       = 0;
1295   s->delay_finish_event       = 0;
1296   s->gapless_switch           = 0;
1297   s->keep_ao_driver_open      = 0;
1298   s->video_channel            = 0;
1299   s->video_decoder_plugin     = NULL;
1300   s->spu_track_map_entries    = 0;
1301   s->counter.headers_audio    = 0;
1302   s->counter.headers_video    = 0;
1303   s->counter.finisheds_audio  = 0;
1304   s->counter.finisheds_video  = 0;
1305   s->demux.action_pending     = 0;
1306   s->demux.input_caps         = 0;
1307   s->demux.thread_created     = 0;
1308   s->demux.thread_running     = 0;
1309   s->err                      = 0;
1310   s->broadcaster              = NULL;
1311   s->index.array              = NULL;
1312   s->s.slave                  = NULL;
1313   s->slave_is_subtitle        = 0;
1314   s->query_input_plugins[0]   = NULL;
1315   s->query_input_plugins[1]   = NULL;
1316   {
1317     int i;
1318     for (i = 1; i < XINE_NUM_SIDE_STREAMS; i++)
1319       s->side_streams[i] = NULL;
1320     for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
1321       s->stream_info[i] = 0;
1322       s->meta_info_public[i] = s->meta_info[i] = NULL;
1323     }
1324   }
1325 #endif
1326   /* no need to memset again
1327   _x_extra_info_reset (&stream->ei[0]);
1328   _x_extra_info_reset (&stream->ei[1]);
1329   */
1330 
1331   /* create a reference counter */
1332   xine_refs_init (&s->refs, (void (*)(void *))xine_side_dispose_internal, &s->s);
1333 
1334   s->audio_decoder_extra_info = m->audio_decoder_extra_info;
1335   s->video_decoder_extra_info = m->video_decoder_extra_info;
1336 
1337   s->side_streams[0] = m;
1338   s->id_flag         = 1 << index;
1339   s->s.xine = m->s.xine;
1340   s->status = XINE_STATUS_IDLE;
1341 
1342   s->video_source.name   = "video source";
1343   s->video_source.type   = XINE_POST_DATA_VIDEO;
1344   s->video_source.data   = &m->s;
1345   s->video_source.rewire = stream_rewire_video;
1346 
1347   s->audio_source.name   = "audio source";
1348   s->audio_source.type   = XINE_POST_DATA_AUDIO;
1349   s->audio_source.data   = &m->s;
1350   s->audio_source.rewire = stream_rewire_audio;
1351 
1352   s->s.spu_decoder_streamtype   = -1;
1353   s->s.audio_out                = m->s.audio_out;
1354   s->audio_channel_user         = -1;
1355   s->s.audio_channel_auto       = -1;
1356   s->audio_decoder_streamtype   = -1;
1357   s->s.spu_channel_auto         = -1;
1358   s->s.spu_channel_letterbox    = -1;
1359   s->spu_channel_pan_scan       = -1;
1360   s->s.spu_channel_user         = -1;
1361   s->s.spu_channel              = -1;
1362   /* Do not flush output when opening/closing yet unused streams (eg subtitle). */
1363   s->finished_naturally         = 1;
1364   s->s.video_out                = m->s.video_out;
1365   s->s.video_driver             = m->s.video_driver;
1366   s->video_decoder_streamtype   = -1;
1367   /* initial master/slave */
1368   s->s.master                   = &s->s;
1369 
1370   s->event.queues = m->event.queues;
1371 
1372   /* these are not used in side streams.
1373   {
1374     pthread_mutexattr_t attr;
1375     pthread_mutexattr_init (&attr);
1376     pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
1377     pthread_mutex_init (&s->frontend_lock, &attr);
1378     pthread_mutexattr_destroy (&attr);
1379   }
1380   xine_refs_init (&stream->current_extra_info_index, _xine_dummy_dest, stream);
1381   pthread_mutex_init (&s->demux.pair, NULL);
1382   pthread_mutex_init (&s->index.lock, NULL);
1383   pthread_mutex_init (&s->event.lock, NULL);
1384   pthread_mutex_init (&s->counter.lock, NULL);
1385   pthread_mutex_init (&s->first_frame.lock, NULL);
1386   pthread_cond_init  (&s->counter.changed, NULL);
1387   pthread_cond_init  (&s->first_frame.reached, NULL);
1388   xine_rwlock_init_default (&s->info_lock);
1389   xine_rwlock_init_default (&s->meta_lock);
1390   */
1391   /* init mutexes and conditions */
1392   pthread_mutex_init (&s->demux.lock, NULL);
1393   pthread_mutex_init (&s->demux.action_lock, NULL);
1394   pthread_cond_init  (&s->demux.resume, NULL);
1395 
1396   /* some user config */
1397   s->disable_decoder_flush_at_discontinuity = m->disable_decoder_flush_at_discontinuity;
1398   s->s.metronom = m->s.metronom;
1399 
1400   /* this will just link to master */
1401   s->s.video_fifo = m->s.video_fifo;
1402   s->s.audio_fifo = m->s.audio_fifo;
1403 
1404   /* osd */
1405   s->s.osd_renderer = m->s.osd_renderer;
1406 
1407   /* register stream */
1408   xine_refs_add (&m->refs, 1);
1409   xine_rwlock_wrlock (&m->info_lock);
1410   m->side_streams[index] = s;
1411   xine_rwlock_unlock (&m->info_lock);
1412   return &s->s;
1413 }
1414 
_x_mrl_unescape(char * mrl)1415 void _x_mrl_unescape (char *mrl) {
1416   static const uint8_t tab_unhex[256] = {
1417 #define nn 128
1418     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1419     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1420     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1421      0, 1, 2, 3, 4, 5, 6, 7, 8, 9,nn,nn,nn,nn,nn,nn,
1422     nn,10,11,12,13,14,15,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1423     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1424     nn,10,11,12,13,14,15,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1425     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1426     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1427     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1428     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1429     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1430     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1431     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1432     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1433     nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn
1434   };
1435   const uint8_t *p = (const uint8_t *)mrl;
1436   uint8_t *q;
1437   /* dont touch until first %xx */
1438   while (*p) {
1439     if (*p == '%') break;
1440     p++;
1441   }
1442   if (!*p)
1443     return;
1444   /* now really unescape */
1445   /* q = (uint8_t *)p ?? */
1446   q = (uint8_t *)mrl + (p - (const uint8_t *)mrl);
1447   while (1) {
1448     uint8_t z = *p++;
1449     if (z == '%') {
1450       uint8_t h = tab_unhex[*p];
1451       if (!(h & nn)) {
1452         z = h;
1453         p++;
1454         h = tab_unhex[*p];
1455         if (!(h & nn)) {
1456           z = (z << 4) | h;
1457           p++;
1458         }
1459       } else if (*p == '%') {
1460         p++;
1461       }
1462     }
1463     *q++ = z;
1464     if (!z) break;
1465   }
1466 #undef nn
1467 }
1468 
_x_mrl_remove_auth(const char * mrl_in)1469 char *_x_mrl_remove_auth(const char *mrl_in)
1470 {
1471   char *mrl = strdup(mrl_in);
1472   char *auth, *p, *at, *host_end;
1473 
1474   /* parse protocol */
1475   if (!(p = strchr(mrl, ':'))) {
1476     /* no protocol means plain filename */
1477     return mrl;
1478   }
1479 
1480   p++; /* skip ':' */
1481   if (*p == '/') p++;
1482   if (*p == '/') p++;
1483 
1484   /* authorization (user[:pass]@hostname) */
1485   auth = p;
1486   host_end = strchr(p, '/');
1487   while ((at = strchr(p, '@')) && at < host_end) {
1488     p = at + 1; /* skip '@' */
1489   }
1490 
1491   if (p != auth) {
1492     while (p[-1]) {
1493       *auth++ = *p++;
1494     }
1495   }
1496 
1497   return mrl;
1498 }
1499 
1500 /* 0x01 (end), 0x02 (alpha), 0x04 (alnum - + .), 0x08 (:), 0x10 (;), 0x20 (#)  */
1501 static const uint8_t tab_parse[256] = {
1502    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1503    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1504    0, 0, 0,32, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 4, 0,
1505    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8,16, 0, 0, 0, 0,
1506    0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1507    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0,
1508    0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1509    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0,
1510    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1511    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1512    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1513    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1514    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1515    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1516    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1517    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1518 };
1519 
1520 /* aka "does path have a protocol prefix" */
_x_path_looks_like_mrl(const char * path)1521 static inline int _x_path_looks_like_mrl (const char *path) {
1522   const uint8_t *p = (const uint8_t *)path;
1523   if (!(tab_parse[*p++] & 0x02))
1524     return 0;
1525   while (tab_parse[*p++] & 0x04) ;
1526   return (p[-1] == ':') && (p[0] == '/');
1527 }
1528 
open_internal(xine_stream_private_t * stream,const char * mrl)1529 static int open_internal (xine_stream_private_t *stream, const char *mrl) {
1530 
1531   static const uint8_t tab_tolower[256] = {
1532       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
1533      16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1534     ' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
1535     '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
1536     '@','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
1537     'p','q','r','s','t','u','v','w','x','y','z','[','\\',']','^','_',
1538     '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
1539     'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',127,
1540     128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
1541     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
1542     160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
1543     176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
1544     192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
1545     208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
1546     224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
1547     240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
1548   };
1549 
1550   uint8_t *buf, *name, *args;
1551   int no_cache = 0;
1552 
1553   if (!mrl) {
1554     xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error while parsing mrl\n"));
1555     stream->err = XINE_ERROR_MALFORMED_MRL;
1556     if (stream->status != XINE_STATUS_IDLE)
1557       stream->status = XINE_STATUS_STOP;
1558     return 0;
1559   }
1560 
1561   lprintf ("opening MRL '%s'...\n", mrl);
1562 
1563   /*
1564    * stop engine if necessary
1565    */
1566 
1567   close_internal (stream);
1568 
1569   lprintf ("engine should be stopped now\n");
1570 
1571   /*
1572    * look for a stream_setup in MRL and try finding an input plugin
1573    */
1574   buf = malloc (32 + strlen (mrl) + 32);
1575   if (!buf)
1576     return 0;
1577   name = buf + 32;
1578   args = NULL;
1579   {
1580     const uint8_t *p = (const uint8_t *)mrl;
1581     uint8_t *prot = NULL, *q = name, z;
1582     /* test protocol prefix */
1583     if (tab_parse[*p] & 0x02) {
1584       while (tab_parse[z = *p] & 0x04) p++, *q++ = z;
1585       if ((q > name) && (z == ':') && (p[1] == '/')) prot = name;
1586     }
1587     if (prot) {
1588       /* split off args at first hash */
1589       while (!(tab_parse[z = *p] & 0x21)) p++, *q++ = z;
1590       *q = 0;
1591       if (z == '#') {
1592         p++;
1593         args = ++q;
1594         while ((*q++ = *p++) != 0) ;
1595       }
1596     } else {
1597       /* raw filename, may contain any number of hashes */
1598       while (1) {
1599         struct stat s;
1600         while (!(tab_parse[z = *p] & 0x21)) p++, *q++ = z;
1601         *q = 0;
1602         /* no need to stat when no hashes found */
1603         if (!args && !z) break;
1604         if (!stat ((const char *)name, &s)) {
1605           args = NULL;
1606           /* no general break yet, beware "/foo/#bar.flv" */
1607         }
1608         if (!z) break;
1609         p++, *q++ = z;
1610         args = q;
1611       }
1612       if (args) args[-1] = 0;
1613     }
1614   }
1615 
1616   {
1617     /*
1618      * find an input plugin
1619      */
1620     stream->s.input_plugin = _x_find_input_plugin (&stream->s, (const char *)name);
1621 
1622     if (stream->s.input_plugin) {
1623       int res;
1624       input_class_t *input_class = stream->s.input_plugin->input_class;
1625 
1626       xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: found input plugin  : %s\n"),
1627                 dgettext(input_class->text_domain ? input_class->text_domain : XINE_TEXTDOMAIN,
1628                          input_class->description));
1629       if (stream->s.input_plugin->input_class->eject_media)
1630         stream->eject_class = stream->s.input_plugin->input_class;
1631       _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_INPUT_PLUGIN,
1632         stream->s.input_plugin->input_class->identifier);
1633 
1634       res = (stream->s.input_plugin->open) (stream->s.input_plugin);
1635       switch(res) {
1636       case 1: /* Open successfull */
1637 	break;
1638       case -1: /* Open unsuccessfull, but correct plugin */
1639 	stream->err = XINE_ERROR_INPUT_FAILED;
1640 	_x_flush_events_queues (&stream->s);
1641         free (buf);
1642 	return 0;
1643       default:
1644 	xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: input plugin cannot open MRL [%s]\n"),mrl);
1645         _x_free_input_plugin (&stream->s, stream->s.input_plugin);
1646 	stream->s.input_plugin = NULL;
1647 	stream->err = XINE_ERROR_INPUT_FAILED;
1648       }
1649     }
1650   }
1651 
1652   if (!stream->s.input_plugin) {
1653     xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: cannot find input plugin for MRL [%s]\n"),mrl);
1654     stream->err = XINE_ERROR_NO_INPUT_PLUGIN;
1655     _x_flush_events_queues (&stream->s);
1656     free (buf);
1657     return 0;
1658   }
1659 
1660   if (args) {
1661     uint8_t *entry = NULL;
1662 
1663     while (*args) {
1664       /* Turn "WhatAGreat:Bullshit[;]" into key="whatagreat" entry="WhatAGreat" value="Bullshit". */
1665       uint8_t *key = buf, *value = NULL;
1666       if (entry)
1667         xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: no value for \"%s\", ignoring.\n"), entry);
1668       entry = args;
1669       {
1670         uint8_t *spos = args + 31, sval = *spos, *q = key, z;
1671         *spos = 0;
1672         while (!(tab_parse[z = *args] & 0x19)) *q++ = tab_tolower[z], args++;
1673         *q = 0;
1674         *spos = sval;
1675         while (!(tab_parse[z = *args] & 0x19)) args++;
1676         if (z == ':') {
1677           *args++ = 0;
1678           value = args;
1679           while (!(tab_parse[z = *args] & 0x11)) args++;
1680         }
1681         if (z == ';')
1682           *args++ = 0;
1683       }
1684 
1685       if (!memcmp (key, "demux", 6)) {
1686         if (value) {
1687           /* demuxer specified by name */
1688           char *demux_name = (char *)value;
1689           _x_mrl_unescape (demux_name);
1690 	  if (!(stream->demux.plugin = _x_find_demux_plugin_by_name (&stream->s, demux_name, stream->s.input_plugin))) {
1691 	    xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: specified demuxer %s failed to start\n"), demux_name);
1692 	    stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1693 	    stream->status = XINE_STATUS_IDLE;
1694             free (buf);
1695 	    return 0;
1696 	  }
1697 
1698           _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1699             stream->demux.plugin->demux_class->identifier);
1700           entry = NULL;
1701         }
1702 	continue;
1703       }
1704 
1705       if (!memcmp (key, "save", 5)) {
1706         if (value) {
1707           /* filename to save */
1708           char *filename = (char *)value;
1709 	  input_plugin_t *input_saver;
1710 
1711           _x_mrl_unescape (filename);
1712 
1713 	  xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: join rip input plugin\n"));
1714           input_saver = _x_rip_plugin_get_instance (&stream->s, filename);
1715 
1716 	  if( input_saver ) {
1717             stream->s.input_plugin = input_saver;
1718 	  } else {
1719             xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error opening rip input plugin instance\n"));
1720 	    stream->err = XINE_ERROR_MALFORMED_MRL;
1721 	    stream->status = XINE_STATUS_IDLE;
1722             free (buf);
1723 	    return 0;
1724 	  }
1725           entry = NULL;
1726         }
1727 	continue;
1728       }
1729 
1730       if (!memcmp (key, "lastdemuxprobe", 15)) {
1731         if (value) {
1732           /* all demuxers will be probed before the specified one */
1733           char *demux_name = (char *)value;
1734           _x_mrl_unescape (demux_name);
1735 	  if (!(stream->demux.plugin = _x_find_demux_plugin_last_probe (&stream->s, demux_name, stream->s.input_plugin))) {
1736             xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: last_probed demuxer %s failed to start\n"), demux_name);
1737 	    stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1738 	    stream->status = XINE_STATUS_IDLE;
1739             free (buf);
1740 	    return 0;
1741 	  }
1742 	  lprintf ("demux and input plugin found\n");
1743 
1744           _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1745             stream->demux.plugin->demux_class->identifier);
1746           entry = NULL;
1747         }
1748 	continue;
1749       }
1750 
1751       if (!memcmp (key, "novideo", 8)) {
1752         _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_VIDEO, 1);
1753         xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring video\n"));
1754         entry = NULL;
1755 	continue;
1756       }
1757 
1758       if (!memcmp (key, "noaudio", 8)) {
1759         _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_AUDIO, 1);
1760         xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring audio\n"));
1761         entry = NULL;
1762 	continue;
1763       }
1764 
1765       if (!memcmp (key, "nospu", 6)) {
1766         _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_SPU, 1);
1767         xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring subpicture\n"));
1768         entry = NULL;
1769 	continue;
1770       }
1771 
1772       if (!memcmp (key, "nocache", 8)) {
1773         no_cache = 1;
1774         xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("input cache plugin disabled\n"));
1775         entry = NULL;
1776 	continue;
1777       }
1778 
1779       if (!memcmp (key, "volume", 7)) {
1780         if (value) {
1781           char *volume = (char *)value;
1782           _x_mrl_unescape (volume);
1783           xine_set_param (&stream->s, XINE_PARAM_AUDIO_VOLUME, atoi (volume));
1784           entry = NULL;
1785         }
1786 	continue;
1787       }
1788 
1789       if (!memcmp (key, "compression", 12)) {
1790         if (value) {
1791           char *compression = (char *)value;
1792           _x_mrl_unescape (compression);
1793           xine_set_param (&stream->s, XINE_PARAM_AUDIO_COMPR_LEVEL, atoi (compression));
1794           entry = NULL;
1795         }
1796 	continue;
1797       }
1798 
1799       if (!memcmp (key, "subtitle", 9)) {
1800         if (value) {
1801           char *subtitle_mrl = (char *)value;
1802 	  /* unescape for xine_open() if the MRL looks like a raw pathname */
1803 	  if (!_x_path_looks_like_mrl(subtitle_mrl))
1804 	    _x_mrl_unescape(subtitle_mrl);
1805           stream->s.slave = xine_stream_new (stream->s.xine, NULL, stream->s.video_out);
1806 	  stream->slave_affection = XINE_MASTER_SLAVE_PLAY | XINE_MASTER_SLAVE_STOP;
1807           if (xine_open (stream->s.slave, subtitle_mrl)) {
1808             xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("subtitle mrl opened '%s'\n"), subtitle_mrl);
1809             stream->s.slave->master = &stream->s;
1810 	    stream->slave_is_subtitle = 1;
1811 	  } else {
1812             xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error opening subtitle mrl\n"));
1813             xine_dispose (stream->s.slave);
1814             stream->s.slave = NULL;
1815 	  }
1816           entry = NULL;
1817         }
1818 	continue;
1819       }
1820 
1821       if (value) {
1822         /* when we got here, the stream setup parameter must be a config entry */
1823         int retval;
1824         value[-1] = ':';
1825         _x_mrl_unescape ((char *)entry);
1826         retval = _x_config_change_opt (stream->s.xine->config, (char *)entry);
1827 	if (retval <= 0) {
1828           value[-1] = 0;
1829 	  if (retval == 0) {
1830             /* the option not found */
1831             xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: unknown config option \"%s\", ignoring.\n"), entry);
1832 	  } else {
1833             /* not permitted to change from MRL */
1834             xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: changing option '%s' from MRL isn't permitted\n"), entry);
1835 	  }
1836 	}
1837         entry = NULL;
1838       }
1839     }
1840     if (entry)
1841       xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: no value for \"%s\", ignoring.\n"), entry);
1842   }
1843 
1844   free (buf);
1845 
1846   /* Nasty xine-ui issue:
1847    * 1. User pauses playback, then opens a playlist.
1848    * 2. Xine-ui grabs a separate stream tied to our "none" output plugins.
1849    * 3. Xine-ui tries to open every playlist item in turn in order to query some info like duration.
1850    *    We dont discuss the performance and security implications thereof here.
1851    *    But we do find that any such open attempt will freeze inside _x_demux_control_headers_done ()
1852    *    below because the engine is still paused.
1853    * Workaround:
1854    *    If fifo's are (nearly) empty, try that live pause hack.
1855    *    If not, unpause for real. */
1856   if (_x_get_fine_speed (&stream->s) == XINE_SPEED_PAUSE) {
1857     if  (stream->s.audio_fifo && (stream->s.audio_fifo->fifo_size < 10)
1858       && stream->s.video_fifo && (stream->s.video_fifo->fifo_size < 10)) {
1859       xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
1860         "xine_open: switching to live pause mode to avoid freeze.\n");
1861       set_speed_internal (stream->side_streams[0], XINE_LIVE_PAUSE_ON);
1862     } else {
1863       xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
1864         "xine_open: unpauseing to avoid freeze.\n");
1865       set_speed_internal (stream->side_streams[0], XINE_FINE_SPEED_NORMAL);
1866     }
1867   }
1868 
1869   no_cache = no_cache || (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_NO_CACHE);
1870   if( !no_cache )
1871     /* enable buffered input plugin (request optimizer) */
1872     stream->s.input_plugin = _x_cache_plugin_get_instance (&stream->s);
1873 
1874   /* Let the plugin request a specific demuxer (if the user hasn't).
1875    * This overrides find-by-content & find-by-extension.
1876    */
1877   if (!stream->demux.plugin)
1878   {
1879     char *default_demux = NULL;
1880     stream->s.input_plugin->get_optional_data (stream->s.input_plugin, &default_demux, INPUT_OPTIONAL_DATA_DEMUXER);
1881     if (default_demux)
1882     {
1883       stream->demux.plugin = _x_find_demux_plugin_by_name (&stream->s, default_demux, stream->s.input_plugin);
1884       if (stream->demux.plugin)
1885       {
1886         lprintf ("demux and input plugin found\n");
1887         _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1888           stream->demux.plugin->demux_class->identifier);
1889       }
1890       else
1891         xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: couldn't load plugin-specified demux %s for >%s<\n"), default_demux, mrl);
1892     }
1893   }
1894 
1895   if (!stream->demux.plugin) {
1896 
1897     /*
1898      * find a demux plugin
1899      */
1900     if (!(stream->demux.plugin = _x_find_demux_plugin (&stream->s, stream->s.input_plugin))) {
1901       xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: couldn't find demux for >%s<\n"), mrl);
1902       stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1903 
1904       stream->status = XINE_STATUS_IDLE;
1905 
1906       /* force the engine to unregister fifo callbacks */
1907       _x_demux_control_nop (&stream->s, BUF_FLAG_END_STREAM);
1908 
1909       return 0;
1910     }
1911     lprintf ("demux and input plugin found\n");
1912 
1913     _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1914       stream->demux.plugin->demux_class->identifier);
1915   }
1916 
1917   {
1918     demux_class_t *demux_class = stream->demux.plugin->demux_class;
1919     xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: found demuxer plugin: %s\n"),
1920               dgettext(demux_class->text_domain ? demux_class->text_domain : XINE_TEXTDOMAIN,
1921                        demux_class->description));
1922   }
1923 
1924   _x_extra_info_reset( stream->current_extra_info );
1925   _x_extra_info_reset( stream->video_decoder_extra_info );
1926   _x_extra_info_reset( stream->audio_decoder_extra_info );
1927 
1928   /* assume handled for now. we will only know for sure after trying
1929    * to init decoders (which should happen when headers are sent)
1930    */
1931   _x_stream_info_set (&stream->s, XINE_STREAM_INFO_VIDEO_HANDLED, 1);
1932   _x_stream_info_set (&stream->s, XINE_STREAM_INFO_AUDIO_HANDLED, 1);
1933 
1934   /*
1935    * send and decode headers
1936    */
1937 
1938   stream->demux.plugin->send_headers (stream->demux.plugin);
1939 
1940   if (stream->demux.plugin->get_status (stream->demux.plugin) != DEMUX_OK) {
1941     if (stream->demux.plugin->get_status (stream->demux.plugin) == DEMUX_FINISHED) {
1942       xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: demuxer is already done. that was fast!\n"));
1943     } else {
1944       xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: demuxer failed to start\n"));
1945     }
1946 
1947     _x_free_demux_plugin (&stream->s, &stream->demux.plugin);
1948 
1949     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "demux disposed\n");
1950 
1951     _x_free_input_plugin (&stream->s, stream->s.input_plugin);
1952     stream->s.input_plugin = NULL;
1953     stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1954 
1955     stream->status = XINE_STATUS_IDLE;
1956 
1957     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "return from\n");
1958     return 0;
1959   }
1960 
1961   _x_demux_control_headers_done (&stream->s);
1962 
1963   stream->status = XINE_STATUS_STOP;
1964 
1965   lprintf ("done\n");
1966   return 1;
1967 }
1968 
xine_open(xine_stream_t * s,const char * mrl)1969 int xine_open (xine_stream_t *s, const char *mrl) {
1970   xine_stream_private_t *stream = (xine_stream_private_t *)s;
1971   xine_private_t *xine = (xine_private_t *)stream->s.xine;
1972   pthread_mutex_t *frontend_lock = &stream->side_streams[0]->frontend_lock;
1973   int ret;
1974 
1975   pthread_mutex_lock (frontend_lock);
1976   pthread_cleanup_push (mutex_cleanup, (void *) frontend_lock);
1977 
1978   lprintf ("open MRL:%s\n", mrl);
1979 
1980   ret = open_internal (stream, mrl);
1981 
1982   if (xine->join_av && mrl && (stream->side_streams[0] == stream)) do {
1983     char nbuf[1024];
1984     struct stat st;
1985     size_t nlen;
1986     xine_stream_private_t *side;
1987     const uint8_t *p, *n, *d;
1988     const char *orig = mrl;
1989     if (!strncasecmp (orig, "file:/", 6))
1990       orig += 6;
1991     n = d = p = (const uint8_t *)orig;
1992     while (1) {
1993       while (*p >= 0x30)
1994         p++;
1995       if ((*p == 0) || (*p == '#'))
1996         break;
1997       if (*p == '/') {
1998         p++;
1999         n = d = p;
2000       } else if (*p == '.') {
2001         d = p;
2002         p++;
2003       } else {
2004         p++;
2005       }
2006     }
2007     nlen = p - (const uint8_t *)orig;
2008     if (nlen > sizeof (nbuf) - 1)
2009       break;
2010     if ((n + 2 > d) || (d[-2] != '_') || (d[0] != '.'))
2011       break;
2012     if ((d[-1] != 'a') && (d[-1] != 'v'))
2013       break;
2014     if (stat (orig, &st))
2015       break;
2016     if (!S_ISREG (st.st_mode))
2017       break;
2018     memcpy (nbuf, orig, nlen);
2019     nbuf[nlen] = 0;
2020     nbuf[d - (const uint8_t *)orig - 1] = d[-1] == 'a' ? 'v' : 'a';
2021     if (stat (nbuf, &st))
2022       break;
2023     if (!S_ISREG (st.st_mode))
2024       break;
2025     side = (xine_stream_private_t *)xine_get_side_stream (&stream->s, 1);
2026     if (!side)
2027       break;
2028     xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
2029       "xine_open: auto joining \"%s\" with \"%s\".\n", orig, nbuf);
2030     open_internal (side, nbuf);
2031   } while (0);
2032 
2033   pthread_cleanup_pop (0);
2034   pthread_mutex_unlock (frontend_lock);
2035 
2036   return ret;
2037 }
2038 
wait_first_frame(xine_stream_private_t * stream)2039 static void wait_first_frame (xine_stream_private_t *stream) {
2040   if (stream->video_decoder_plugin || stream->audio_decoder_plugin) {
2041     pthread_mutex_lock (&stream->first_frame.lock);
2042     if (stream->first_frame.flag > 0) {
2043       struct timespec ts = {0, 0};
2044       xine_gettime (&ts);
2045       ts.tv_sec += 10;
2046       pthread_cond_timedwait(&stream->first_frame.reached, &stream->first_frame.lock, &ts);
2047     }
2048     pthread_mutex_unlock (&stream->first_frame.lock);
2049   }
2050 }
2051 
play_internal(xine_stream_private_t * stream,int start_pos,int start_time)2052 static int play_internal (xine_stream_private_t *stream, int start_pos, int start_time) {
2053   xine_private_t *xine = (xine_private_t *)stream->s.xine;
2054   int        flush;
2055   int        first_frame_flag = 3;
2056   int        demux_status;
2057   uint32_t   input_is_seekable = 1;
2058   struct     timespec ts1 = {0, 0}, ts2 = {0, 0};
2059   struct {
2060     xine_stream_private_t *s;
2061     uint32_t flags;
2062   } sides[XINE_NUM_SIDE_STREAMS + 1], *sp, *sp2;
2063 
2064   if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2065     xine_gettime (&ts1);
2066     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
2067       "play_internal (%d.%03d, %d)\n", start_time / 1000, start_time % 1000, start_pos);
2068   }
2069 
2070   /* list the streams (master and sides) with a demux. */
2071   {
2072     unsigned int u;
2073     sp = sides;
2074     xine_rwlock_rdlock (&stream->info_lock);
2075     for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
2076       xine_stream_private_t *side = stream->side_streams[u];
2077       if (side && side->demux.plugin) {
2078         sp->s = side;
2079         sp->flags = 0;
2080         sp++;
2081       }
2082     }
2083     xine_rwlock_unlock (&stream->info_lock);
2084     sp->s = NULL;
2085     sp->flags = 0;
2086   }
2087 
2088   if (!sides[0].s) {
2089     xine_log (stream->s.xine, XINE_LOG_MSG, _("xine_play: no demux available\n"));
2090     stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
2091 
2092     return 0;
2093   }
2094 
2095   if (start_pos || start_time) {
2096     stream->finished_naturally = 0;
2097     first_frame_flag = 2;
2098   }
2099   flush = (stream->s.master == &stream->s) && !stream->gapless_switch && !stream->finished_naturally;
2100   if (!flush)
2101     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: using gapless switch.\n");
2102 
2103   /* hint demuxer thread we want to interrupt it */
2104   sp = sides;
2105   do {
2106     pthread_mutex_lock (&sp->s->demux.action_lock);
2107     sp->s->demux.action_pending += 0x10001;
2108     if (!(sp->s->demux.input_caps & (INPUT_CAP_SEEKABLE | INPUT_CAP_SLOW_SEEKABLE)))
2109       input_is_seekable = 0;
2110     pthread_mutex_unlock (&sp->s->demux.action_lock);
2111     sp++;
2112   } while (sp->s);
2113 
2114   /* WTF??
2115    * TJ. OK these calls involve lock/unlock of the fifo mutexes.
2116    * Demux will do that again later by fifo->put ().
2117    * At least with x86 Linux, such a sequence forces a data cache sync from this thread
2118    * to the demux thread. This way, demux will see demux.action_pending > 0 early,
2119    * without the need to grab demux.action_lock for every iteration.
2120    * Reduces response delay by average 20ms. */
2121   (void)stream->s.video_fifo->size (stream->s.video_fifo);
2122   (void)stream->s.audio_fifo->size (stream->s.audio_fifo);
2123 
2124   /* ignore speed changes (net_buf_ctrl causes deadlocks while seeking ...) */
2125   lock_run (stream, 1);
2126 
2127   xine->port_ticket->acquire (xine->port_ticket, 1);
2128 
2129   /* only flush/discard output ports on master streams */
2130   if (flush) {
2131     /* discard audio/video buffers to get engine going and take the lock faster */
2132     if (stream->s.audio_out)
2133       stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
2134     if (stream->s.video_out)
2135       stream->s.video_out->set_property (stream->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
2136     /* freeze safety (discontinuity wait?) when there are multiple streams.
2137      * or, when all input is seekable, suspend faster this way. */
2138     if (sides[1].s || input_is_seekable) {
2139       stream->s.video_fifo->clear (stream->s.video_fifo);
2140       stream->s.audio_fifo->clear (stream->s.audio_fifo);
2141     }
2142   }
2143 
2144   sp = sides;
2145   do {
2146     pthread_mutex_lock (&sp->s->demux.lock);
2147     /* demux.lock taken. now demuxer is suspended. unblock io for seeking. */
2148     pthread_mutex_lock (&sp->s->demux.action_lock);
2149     sp->s->demux.action_pending -= 0x00001;
2150     pthread_mutex_unlock (&sp->s->demux.action_lock);
2151     sp++;
2152   } while (sp->s);
2153 
2154   if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2155     int diff;
2156     xine_gettime (&ts2);
2157     diff = (int)(ts2.tv_nsec - ts1.tv_nsec) / 1000000;
2158     diff += (ts2.tv_sec - ts1.tv_sec) * 1000;
2159     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: ...demux suspended after %dms.\n", diff);
2160   }
2161 
2162   /* set normal speed again (now that demuxer/input pair is suspended)
2163    * some input plugin may have changed speed by itself, we must ensure
2164    * the engine is not paused.
2165    */
2166   if (_x_get_fine_speed (&stream->s) != XINE_FINE_SPEED_NORMAL)
2167     set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
2168 
2169   /*
2170    * start/seek demux
2171    */
2172 
2173   pthread_mutex_lock (&stream->demux.pair);
2174   stream->demux.max_seek_bufs = sides[1].s ? 1 : 0xffffffff;
2175   pthread_mutex_unlock (&stream->demux.pair);
2176 
2177   /* seek to new position (no data is sent to decoders yet) */
2178   sp = sides;
2179   do {
2180     xine_stream_private_t *s;
2181     int r;
2182     int32_t vtime = 0;
2183     if (!sides[1].s)
2184       break;
2185     sp2 = sides;
2186     do {
2187       if (sp2->s->demux.plugin->get_capabilities (sp2->s->demux.plugin) & DEMUX_CAP_VIDEO_TIME)
2188         break;
2189       sp2++;
2190     } while (sp2->s);
2191     if (!sp2->s)
2192       break;
2193     s = sp2->s;
2194     sp2->s = sides[0].s;
2195     sides[0].s = s;
2196     sp++;
2197     r = sides[0].s->demux.plugin->seek (sides[0].s->demux.plugin,
2198       start_pos, start_time, sides[0].s->demux.thread_running);
2199     sides[0].flags = r == DEMUX_OK ? 1 : 0;
2200     if (r != DEMUX_OK)
2201       break;
2202     if (sides[0].s->demux.plugin->get_optional_data (sides[0].s->demux.plugin, &vtime,
2203         DEMUX_OPTIONAL_DATA_VIDEO_TIME) != DEMUX_OPTIONAL_SUCCESS)
2204       break;
2205     start_pos = 0;
2206     start_time = vtime;
2207   } while (0);
2208   do {
2209     int r = sp->s->demux.plugin->seek (sp->s->demux.plugin,
2210       start_pos, start_time, sp->s->demux.thread_running);
2211     sp->flags = r == DEMUX_OK ? 1 : 0;
2212     sp++;
2213   } while (sp->s);
2214 
2215   /* only flush/discard output ports on master streams */
2216   if (flush) {
2217     if (stream->s.audio_out)
2218       stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
2219     if (stream->s.video_out)
2220       stream->s.video_out->set_property (stream->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
2221   } else {
2222     stream->s.metronom->handle_audio_discontinuity (stream->s.metronom, DISC_GAPLESS, 0);
2223   }
2224 
2225   xine->port_ticket->release (xine->port_ticket, 1);
2226   unlock_run (stream);
2227 
2228   /* before resuming the demuxer, set first_frame_flag */
2229   pthread_mutex_lock (&stream->first_frame.lock);
2230   stream->first_frame.flag = first_frame_flag;
2231   pthread_mutex_unlock (&stream->first_frame.lock);
2232 
2233   /* before resuming the demuxer, reset current position information */
2234   xine_current_extra_info_reset (stream);
2235 
2236   /* now resume demuxer thread if it is running already */
2237   demux_status = 0;
2238   sp = sides;
2239   do {
2240     sp->flags |= sp->s->demux.thread_running ? 2 : 0;
2241     pthread_mutex_unlock (&sp->s->demux.lock);
2242     /* now that demux lock is released, resume demux. */
2243     pthread_mutex_lock (&sp->s->demux.action_lock);
2244     sp->s->demux.action_pending -= 0x10000;
2245     if (sp->s->demux.action_pending <= 0)
2246       pthread_cond_signal (&sp->s->demux.resume);
2247     pthread_mutex_unlock (&sp->s->demux.action_lock);
2248     /* seek OK but not running? try restart. */
2249     if (sp->flags == 1) {
2250       if (_x_demux_start_thread (&sp->s->s) >= 0)
2251         sp->flags = 3;
2252     }
2253     if (sp->flags == 3)
2254       demux_status++;
2255     sp++;
2256   } while (sp->s);
2257 
2258   if (!demux_status)
2259     goto demux_failed;
2260 
2261   stream->status = XINE_STATUS_PLAY;
2262   stream->finished_naturally = 0;
2263 
2264 
2265   /* Wait until the first frame produced is displayed
2266    * see video_out.c
2267    */
2268   wait_first_frame (stream);
2269   {
2270     extra_info_t info;
2271     int video_seek_count = xine_current_extra_info_get (stream, &info);
2272     if (info.seek_count != video_seek_count)
2273     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: warning: seek count still %d != %d.\n",
2274       info.seek_count, video_seek_count);
2275   }
2276 
2277   if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2278     int diff;
2279     xine_gettime (&ts2);
2280     diff = (int)(ts2.tv_nsec - ts1.tv_nsec) / 1000000;
2281     diff += (ts2.tv_sec - ts1.tv_sec) * 1000;
2282     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: ...done after %dms.\n", diff);
2283   }
2284 
2285   return 1;
2286 
2287  demux_failed:
2288   xine_log (stream->s.xine, XINE_LOG_MSG, _("xine_play: demux failed to start\n"));
2289 
2290   stream->err = XINE_ERROR_DEMUX_FAILED;
2291   pthread_mutex_lock (&stream->first_frame.lock);
2292   stream->first_frame.flag = 0;
2293   // no need to signal: wait is done only in this function.
2294   pthread_mutex_unlock (&stream->first_frame.lock);
2295   return 0;
2296 }
2297 
xine_play(xine_stream_t * s,int start_pos,int start_time)2298 int xine_play (xine_stream_t *s, int start_pos, int start_time) {
2299   xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
2300   int ret;
2301 
2302   if (!stream)
2303     return 0;
2304   m = stream->side_streams[0];
2305 
2306   pthread_mutex_lock (&m->frontend_lock);
2307   pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
2308 
2309   m->delay_finish_event = 0;
2310 
2311   ret = play_internal (m, start_pos, start_time);
2312   if (m->s.slave && (m->slave_affection & XINE_MASTER_SLAVE_PLAY) )
2313     xine_play (m->s.slave, start_pos, start_time);
2314 
2315   m->gapless_switch = 0;
2316 
2317   pthread_cleanup_pop (0);
2318   pthread_mutex_unlock (&m->frontend_lock);
2319 
2320   return ret;
2321 }
2322 
xine_eject(xine_stream_t * s)2323 int xine_eject (xine_stream_t *s) {
2324   xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
2325   int status;
2326 
2327   if (!stream)
2328     return 0;
2329   m = stream->side_streams[0];
2330 
2331   if (!m->eject_class)
2332     return 0;
2333 
2334   pthread_mutex_lock (&m->frontend_lock);
2335   pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
2336 
2337   status = 0;
2338   /* only eject, if we are stopped OR a different input plugin is playing */
2339   if (m->eject_class && m->eject_class->eject_media &&
2340       ((m->status == XINE_STATUS_STOP) ||
2341       m->eject_class != m->s.input_plugin->input_class)) {
2342 
2343     status = m->eject_class->eject_media (m->eject_class);
2344   }
2345 
2346   pthread_cleanup_pop (0);
2347   pthread_mutex_unlock (&m->frontend_lock);
2348 
2349   return status;
2350 }
2351 
xine_dispose_internal(xine_stream_private_t * stream)2352 static void xine_dispose_internal (xine_stream_private_t *stream) {
2353   xine_t *xine = stream->s.xine;
2354 
2355   lprintf("stream: %p\n", (void*)stream);
2356 
2357   xine->config->unregister_callbacks (xine->config, NULL, NULL, stream, sizeof (*stream));
2358 
2359   pthread_mutex_lock (&xine->streams_lock);
2360   {
2361     xine_list_iterator_t ite = xine_list_find (xine->streams, stream);
2362     if (ite)
2363       xine_list_remove (xine->streams, ite);
2364   }
2365   /* keep xine instance open for this */
2366   stream->s.metronom->exit (stream->s.metronom);
2367   pthread_mutex_unlock (&xine->streams_lock);
2368 
2369   pthread_mutex_destroy (&stream->frontend_lock);
2370   pthread_mutex_destroy (&stream->index.lock);
2371   pthread_cond_destroy  (&stream->first_frame.reached);
2372   pthread_mutex_destroy (&stream->first_frame.lock);
2373   pthread_cond_destroy  (&stream->counter.changed);
2374   pthread_mutex_destroy (&stream->counter.lock);
2375   pthread_mutex_destroy (&stream->event.lock);
2376   pthread_cond_destroy  (&stream->demux.resume);
2377   pthread_mutex_destroy (&stream->demux.pair);
2378   pthread_mutex_destroy (&stream->demux.action_lock);
2379   pthread_mutex_destroy (&stream->demux.lock);
2380   xine_rwlock_destroy   (&stream->meta_lock);
2381   xine_rwlock_destroy   (&stream->info_lock);
2382 
2383   xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
2384 
2385   xine_list_delete (stream->event.queues);
2386 
2387   free (stream->index.array);
2388   free (stream);
2389 }
2390 
xine_dispose(xine_stream_t * s)2391 void xine_dispose (xine_stream_t *s) {
2392   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2393   /* decrease the reference counter
2394    * if there is no more reference on this stream, the xine_dispose_internal
2395    * function is called
2396    */
2397   if (!stream)
2398     return;
2399   /* never dispose side streams directly. */
2400   if (stream->side_streams[0] != stream)
2401     return;
2402 
2403   xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "xine_dispose\n");
2404   stream->status = XINE_STATUS_QUIT;
2405 
2406   xine_close (&stream->s);
2407 
2408   if (stream->s.master != &stream->s) {
2409     stream->s.master->slave = NULL;
2410   }
2411   if (stream->s.slave && (stream->s.slave->master == &stream->s)) {
2412     stream->s.slave->master = NULL;
2413   }
2414 
2415   {
2416     unsigned int u;
2417     for (u = 1; u < XINE_NUM_SIDE_STREAMS; u++) {
2418       xine_stream_private_t *side = stream->side_streams[u];
2419       if (side)
2420         xine_refs_sub (&side->refs, 1);
2421     }
2422   }
2423 
2424   if(stream->broadcaster)
2425     _x_close_broadcaster(stream->broadcaster);
2426 
2427   /* Demuxers mpeg, mpeg_block and yuv_frames may send video pool buffers
2428    * to audio fifo. Fifos should be empty at this point. For safety,
2429    * shut down audio first anyway.
2430    */
2431   xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "shutdown audio\n");
2432   _x_audio_decoder_shutdown (&stream->s);
2433 
2434   xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "shutdown video\n");
2435   _x_video_decoder_shutdown (&stream->s);
2436 
2437   if (stream->s.osd_renderer)
2438     stream->s.osd_renderer->close (stream->s.osd_renderer);
2439 
2440   /* Remove the reference that the stream was created with. */
2441   xine_refs_sub (&stream->refs, 1);
2442 }
2443 
2444 #ifdef WIN32
2445 static int xine_wsa_users = 0;
2446 #endif
2447 
xine_exit(xine_t * this_gen)2448 void xine_exit (xine_t *this_gen) {
2449   xine_private_t *this = (xine_private_t *)this_gen;
2450   if (this->x.streams) {
2451     int n = 10;
2452     /* XXX: streams kill themselves via their refs hook. */
2453     while (n--) {
2454       xine_stream_private_t *stream = NULL;
2455       xine_list_iterator_t ite;
2456 
2457       pthread_mutex_lock (&this->x.streams_lock);
2458       ite = NULL;
2459       while (1) {
2460         stream = xine_list_next_value (this->x.streams, &ite);
2461         if (!ite || (stream && (&stream->s != XINE_ANON_STREAM)))
2462           break;
2463       }
2464       if (!ite) {
2465         pthread_mutex_unlock (&this->x.streams_lock);
2466         break;
2467       }
2468       /* stream->refcounter->lock might be taken already */
2469       {
2470         int i = xine_refs_add (&stream->refs, 0);
2471         pthread_mutex_unlock (&this->x.streams_lock);
2472         xprintf (&this->x, XINE_VERBOSITY_LOG,
2473                  "xine_exit: BUG: stream %p still open (%d refs), waiting.\n",
2474                  (void*)stream, i);
2475       }
2476       if (n) {
2477         xine_usec_sleep (50000);
2478       } else {
2479 #ifdef FORCE_STREAM_SHUTDOWN
2480         /* might raise even more heap damage, disabled for now */
2481         xprintf (&this->x, XINE_VERBOSITY_LOG,
2482                  "xine_exit: closing stream %p.\n",
2483                  (void*)stream);
2484         stream->refcounter->count = 1;
2485         xine_dispose (stream);
2486         n = 1;
2487 #endif
2488       }
2489     }
2490     xine_list_delete (this->x.streams);
2491     pthread_mutex_destroy (&this->x.streams_lock);
2492   }
2493 
2494   if (this->x.config)
2495     this->x.config->unregister_callbacks (this->x.config, NULL, NULL, this, sizeof (*this));
2496 
2497   xprintf (&this->x, XINE_VERBOSITY_DEBUG, "xine_exit: bye!\n");
2498 
2499   _x_dispose_plugins (&this->x);
2500 
2501   if (this->x.clock)
2502     this->x.clock->exit (this->x.clock);
2503 
2504   if (this->x.config)
2505     this->x.config->dispose (this->x.config);
2506 
2507   if(this->port_ticket)
2508     this->port_ticket->dispose(this->port_ticket);
2509 
2510   pthread_cond_destroy (&this->speed_change_done);
2511   pthread_mutex_destroy (&this->speed_change_lock);
2512 
2513   {
2514     int i;
2515     for (i = 0; i < XINE_LOG_NUM; i++)
2516       if (this->x.log_buffers[i])
2517         this->x.log_buffers[i]->dispose (this->x.log_buffers[i]);
2518   }
2519   pthread_mutex_destroy(&this->log_lock);
2520 
2521 #if defined(WIN32)
2522   if (xine_wsa_users) {
2523     if (--xine_wsa_users == 0)
2524       WSACleanup ();
2525   }
2526 #endif
2527 
2528   xdgWipeHandle (&this->x.basedir_handle);
2529 
2530   free (this);
2531 }
2532 
xine_new(void)2533 xine_t *xine_new (void) {
2534   xine_private_t *this;
2535 
2536   this = calloc (1, sizeof (*this));
2537   if (!this)
2538     return NULL;
2539 #ifndef HAVE_ZERO_SAFE_MEM
2540   this->x.plugin_catalog = NULL;
2541   this->x.save_path      = NULL;
2542   this->x.streams        = NULL;
2543   this->x.clock          = NULL;
2544   this->port_ticket      = NULL;
2545   this->speed_change_flags = 0;
2546 #endif
2547 
2548   pthread_mutex_init (&this->speed_change_lock, NULL);
2549   pthread_cond_init (&this->speed_change_done, NULL);
2550 
2551 #ifdef ENABLE_NLS
2552   /*
2553    * i18n
2554    */
2555 
2556   bindtextdomain(XINE_TEXTDOMAIN, XINE_LOCALEDIR);
2557 #endif
2558 
2559   /*
2560    * config
2561    */
2562 
2563   this->x.config = _x_config_init ();
2564   if (!this->x.config) {
2565     free(this);
2566     return NULL;
2567   }
2568 
2569   /*
2570    * log buffers
2571    */
2572   memset (this->x.log_buffers, 0, sizeof (this->x.log_buffers));
2573   pthread_mutex_init (&this->log_lock, NULL);
2574 
2575 #ifdef WIN32
2576   if (!xine_wsa_users) {
2577     /* WinSock Library Init. */
2578     WSADATA Data;
2579     int i_err = WSAStartup (MAKEWORD (1, 1), &Data);
2580     if (i_err) {
2581       fprintf (stderr, "error: can't initiate WinSocks, error %i\n", i_err);
2582     } else {
2583       xine_wsa_users++;
2584     }
2585   } else {
2586     xine_wsa_users++;
2587   }
2588 #endif /* WIN32 */
2589 
2590   this->x.verbosity = XINE_VERBOSITY_NONE;
2591 
2592   return &this->x;
2593 }
2594 
xine_engine_set_param(xine_t * this,int param,int value)2595 void xine_engine_set_param(xine_t *this, int param, int value) {
2596 
2597   if(this) {
2598     switch(param) {
2599 
2600     case XINE_ENGINE_PARAM_VERBOSITY:
2601       this->verbosity = value;
2602       break;
2603 
2604     default:
2605       lprintf("Unknown parameter %d\n", param);
2606       break;
2607     }
2608   }
2609 }
2610 
xine_engine_get_param(xine_t * this,int param)2611 int xine_engine_get_param(xine_t *this, int param) {
2612 
2613   if(this) {
2614     switch(param) {
2615 
2616     case XINE_ENGINE_PARAM_VERBOSITY:
2617       return this->verbosity;
2618       break;
2619 
2620     default:
2621       lprintf("Unknown parameter %d\n", param);
2622       break;
2623     }
2624   }
2625   return -1;
2626 }
2627 
config_demux_strategy_cb(void * this_gen,xine_cfg_entry_t * entry)2628 static void config_demux_strategy_cb (void *this_gen, xine_cfg_entry_t *entry) {
2629   xine_t *this = (xine_t *)this_gen;
2630 
2631   this->demux_strategy = entry->num_value;
2632 }
2633 
config_save_cb(void * this_gen,xine_cfg_entry_t * entry)2634 static void config_save_cb (void *this_gen, xine_cfg_entry_t *entry) {
2635   xine_t *this = (xine_t *)this_gen;
2636   char homedir_trail_slash[strlen(xine_get_homedir()) + 2];
2637 
2638   sprintf(homedir_trail_slash, "%s/", xine_get_homedir());
2639   if (entry->str_value[0] &&
2640       (entry->str_value[0] != '/' || strstr(entry->str_value, "/.") ||
2641        strcmp(entry->str_value, xine_get_homedir()) == 0 ||
2642        strcmp(entry->str_value, homedir_trail_slash) == 0)) {
2643     xine_stream_t *stream;
2644     xine_list_iterator_t ite;
2645 
2646     xine_log(this, XINE_LOG_MSG,
2647 	     _("xine: The specified save_dir \"%s\" might be a security risk.\n"), entry->str_value);
2648 
2649     pthread_mutex_lock(&this->streams_lock);
2650     ite = NULL;
2651     if ((stream = xine_list_next_value (this->streams, &ite))) {
2652       _x_message(stream, XINE_MSG_SECURITY, _("The specified save_dir might be a security risk."), NULL);
2653     }
2654     pthread_mutex_unlock(&this->streams_lock);
2655   }
2656 
2657   this->save_path = entry->str_value;
2658 }
2659 
xine_set_flags(xine_t * this_gen,int flags)2660 void xine_set_flags (xine_t *this_gen, int flags)
2661 {
2662   xine_private_t *this = (xine_private_t *)this_gen;
2663   this->flags = flags;
2664 }
2665 
_x_query_network_timeout(xine_t * xine_gen)2666 int _x_query_network_timeout (xine_t *xine_gen) {
2667   xine_private_t *xine = (xine_private_t *)xine_gen;
2668   return xine ? xine->network_timeout : 30;
2669 }
2670 
network_timeout_cb(void * this_gen,xine_cfg_entry_t * entry)2671 static void network_timeout_cb (void *this_gen, xine_cfg_entry_t *entry) {
2672   xine_private_t *this = (xine_private_t *)this_gen;
2673   this->network_timeout = entry->num_value;
2674 }
2675 
2676 #ifdef ENABLE_IPV6
ip_pref_cb(void * this_gen,xine_cfg_entry_t * entry)2677 static void ip_pref_cb (void *this_gen, xine_cfg_entry_t *entry) {
2678   xine_private_t *this = (xine_private_t *)this_gen;
2679   this->ip_pref = entry->num_value;
2680 }
2681 #endif
2682 
join_av_cb(void * this_gen,xine_cfg_entry_t * entry)2683 static void join_av_cb (void *this_gen, xine_cfg_entry_t *entry) {
2684   xine_private_t *this = (xine_private_t *)this_gen;
2685   this->join_av = entry->num_value;
2686 }
2687 
xine_init(xine_t * this_gen)2688 void xine_init (xine_t *this_gen) {
2689   xine_private_t *this = (xine_private_t *)this_gen;
2690 
2691   /* First of all, initialise libxdg-basedir as it's used by plugins. */
2692   setenv ("HOME", xine_get_homedir (), 0); /* libxdg-basedir needs $HOME */
2693   xdgInitHandle (&this->x.basedir_handle);
2694 
2695   /* debug verbosity override */
2696   {
2697     int v = 0;
2698     const uint8_t *s = (const uint8_t *)getenv ("LIBXINE_VERBOSITY"), *t = s;
2699     uint8_t z;
2700     if (s) {
2701       while ((z = *s++ ^ '0') < 10)
2702         v = 10 * v + z;
2703       if (s > t + 1)
2704         this->x.verbosity = v;
2705     }
2706   }
2707 
2708   /*
2709    * locks
2710    */
2711   pthread_mutex_init (&this->x.streams_lock, NULL);
2712 
2713   /* initialize color conversion tables and functions */
2714   init_yuv_conversion();
2715 
2716   /* probe for optimized memcpy or config setting */
2717   xine_probe_fast_memcpy (&this->x);
2718 
2719   /*
2720    * plugins
2721    */
2722   XINE_PROFILE (_x_scan_plugins (&this->x));
2723 
2724 #ifdef HAVE_SETLOCALE
2725   if (!setlocale(LC_CTYPE, ""))
2726     xprintf (&this->x, XINE_VERBOSITY_LOG, _("xine: locale not supported by C library\n"));
2727 #endif
2728 
2729   /*
2730    * content detection strategy
2731    */
2732   {
2733     static const char *const demux_strategies[] = {"default", "reverse", "content", "extension", NULL};
2734     this->x.demux_strategy = this->x.config->register_enum (
2735       this->x.config, "engine.demux.strategy", 0,
2736       (char **)demux_strategies,
2737       _("media format detection strategy"),
2738       _("xine offers various methods to detect the media format of input to play. "
2739 	"The individual values are:\n\n"
2740 	"default\n"
2741 	"First try to detect by content, then by file name extension.\n\n"
2742 	"reverse\n"
2743 	"First try to detect by file name extension, then by content.\n\n"
2744 	"content\n"
2745 	"Detect by content only.\n\n"
2746 	"extension\n"
2747 	"Detect by file name extension only.\n"),
2748       20, config_demux_strategy_cb, this);
2749   }
2750 
2751   /*
2752    * save directory
2753    */
2754   this->x.save_path  = this->x.config->register_filename (
2755       this->x.config,
2756       "media.capture.save_dir", "", XINE_CONFIG_STRING_IS_DIRECTORY_NAME,
2757       _("directory for saving streams"),
2758       _("When using the stream save feature, files will be written only into this directory.\n"
2759 	"This setting is security critical, because when changed to a different directory, xine "
2760 	"can be used to fill files in it with arbitrary content. So you should be careful that "
2761 	"the directory you specify is robust against any content in any file."),
2762       XINE_CONFIG_SECURITY, config_save_cb, this);
2763 
2764   /*
2765    * implicit configuration changes
2766    */
2767   this->x.config->register_bool (this->x.config,
2768       "misc.implicit_config", 0,
2769       _("allow implicit changes to the configuration (e.g. by MRL)"),
2770       _("If enabled, you allow xine to change your configuration without "
2771 	"explicit actions from your side. For example configuration changes "
2772 	"demanded by MRLs or embedded into playlist will be executed.\n"
2773 	"This setting is security critcal, because xine can receive MRLs or "
2774 	"playlists from untrusted remote sources. If you allow them to "
2775 	"arbitrarily change your configuration, you might end with a totally "
2776 	"messed up xine."),
2777       XINE_CONFIG_SECURITY, NULL, this);
2778 
2779   /*
2780    * timeout for network I/O to avoid freezes
2781    */
2782   this->network_timeout = this->x.config->register_num (this->x.config,
2783       "media.network.timeout", 30,
2784       _("Timeout for network stream reading (in seconds)"),
2785       _("Specifies the timeout when reading from network streams, in seconds. "
2786         "Too low values might stop streaming when the source is slow or the "
2787         "bandwidth is occupied, too high values will freeze the player if the "
2788         "connection is lost."),
2789       0, network_timeout_cb, this);
2790 
2791 #ifdef ENABLE_IPV6
2792   /*
2793    * network ip version
2794    */
2795   {
2796     static const char *const ip_versions[] = {"auto", "IPv4", "IPv4, IPv6", "IPv6, IPv4", NULL};
2797     this->ip_pref = this->x.config->register_enum (
2798       this->x.config, "media.network.ip_version", 1,
2799       (char **)ip_versions,
2800       _("Internet Protocol version(s) to use"),
2801       _("\"auto\" just tries what the name query returned.\n"
2802         "Otherwise, IPv4 may offer more compatibility and privacy."),
2803       20, ip_pref_cb, this);
2804   }
2805 #endif
2806 
2807   /*
2808    * auto join separate audio/video files (testing the side stream feature).
2809    */
2810   this->join_av = this->x.config->register_bool (this->x.config,
2811       "media.files.join_av", 0,
2812       _("Auto join separate audio/video files"),
2813       _("When opening an audio only file \"foo_a.ext\", assume that \"foo_v.ext\" "
2814         "contains the missing video track for it, and vice versa.\n"
2815         "This mainly serves as a test for engine side streams."),
2816       20, join_av_cb, this);
2817 
2818   /*
2819    * keep track of all opened streams
2820    */
2821   this->x.streams = xine_list_new ();
2822 
2823   /*
2824    * start metronom clock
2825    */
2826 
2827   this->x.clock = _x_metronom_clock_init (&this->x);
2828 
2829   this->x.clock->start_clock (this->x.clock, 0);
2830 
2831   /*
2832    * tickets
2833    */
2834   this->port_ticket = ticket_init();
2835 }
2836 
_x_select_spu_channel(xine_stream_t * s,int channel)2837 void _x_select_spu_channel (xine_stream_t *s, int channel) {
2838   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2839   xine_private_t *xine = (xine_private_t *)stream->s.xine;
2840   xine_stream_private_t *substream = NULL;
2841 
2842   stream = stream->side_streams[0];
2843   substream = (xine_stream_private_t *)stream->s.slave;
2844 
2845   pthread_mutex_lock (&stream->frontend_lock);
2846   stream->s.spu_channel_user = (channel >= -2 ? channel : -2);
2847 
2848   xine->port_ticket->acquire (xine->port_ticket, 1);
2849 
2850   switch (stream->s.spu_channel_user) {
2851   case -2:
2852     stream->s.spu_channel = -1;
2853     break;
2854   case -1:
2855     if (substream)
2856 	stream->s.spu_channel = substream->s.spu_channel_auto;
2857     else
2858 	stream->s.spu_channel = stream->s.spu_channel_auto;
2859     break;
2860   default:
2861     stream->s.spu_channel = stream->s.spu_channel_user;
2862   }
2863   lprintf ("set to %d\n", stream->s.spu_channel);
2864 
2865   xine->port_ticket->release (xine->port_ticket, 1);
2866 
2867   pthread_mutex_unlock (&stream->frontend_lock);
2868 
2869   if (substream)
2870   {
2871       pthread_mutex_lock (&substream->frontend_lock);
2872       substream->s.spu_channel = stream->s.spu_channel;
2873       substream->s.spu_channel_user = stream->s.spu_channel_user;
2874       pthread_mutex_unlock (&substream->frontend_lock);
2875   }
2876 }
2877 
_x_get_current_info(xine_stream_t * s,extra_info_t * extra_info,int size)2878 void _x_get_current_info (xine_stream_t *s, extra_info_t *extra_info, int size) {
2879   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2880 
2881   stream = stream->side_streams[0];
2882 
2883   if (!extra_info || (size <= 0)) {
2884     return;
2885   } else if ((size_t)size < sizeof (*extra_info)) {
2886     extra_info_t info;
2887     xine_current_extra_info_get (stream, &info);
2888     memcpy (extra_info, &info, size);
2889   } else {
2890     xine_current_extra_info_get (stream, extra_info);
2891   }
2892 }
2893 
2894 
xine_get_status(xine_stream_t * s)2895 int xine_get_status (xine_stream_t *s) {
2896   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2897   /* phonon bug */
2898   if (!stream) {
2899     printf ("xine_get_status: BUG: stream = NULL.\n");
2900     return XINE_STATUS_QUIT;
2901   }
2902   stream = stream->side_streams[0];
2903   return stream->status;
2904 }
2905 
2906 /*
2907  * trick play
2908  */
2909 
_x_set_fine_speed(xine_stream_t * s,int speed)2910 void _x_set_fine_speed (xine_stream_t *s, int speed) {
2911   xine_stream_private_t *stream = (xine_stream_private_t *)s;
2912   xine_private_t *xine = (xine_private_t *)stream->s.xine;
2913   uint32_t speed_change_flags;
2914 
2915   stream = stream->side_streams[0];
2916 
2917   /* net_buf_ctrl may have 2 threads trying to pause with ticket held in parallel.
2918    * Avoid that freeze like this:
2919    * - Hold speed_change_lock for finite time only.
2920    * - While changing speed, remember latest speed wishes from elsewhere,
2921    *   and apply them after the current one. */
2922   pthread_mutex_lock (&xine->speed_change_lock);
2923   speed_change_flags = xine->speed_change_flags;
2924   if (speed_change_flags & SPEED_FLAG_IGNORE_CHANGE) {
2925     pthread_mutex_unlock (&xine->speed_change_lock);
2926     return;
2927   }
2928   if (speed_change_flags & SPEED_FLAG_CHANGING) {
2929     if ((speed == XINE_LIVE_PAUSE_ON) || (speed == XINE_LIVE_PAUSE_OFF)) {
2930       xine->speed_change_flags = speed_change_flags | SPEED_FLAG_WANT_LIVE;
2931       xine->speed_change_new_live = speed;
2932       pthread_mutex_unlock (&xine->speed_change_lock);
2933       return;
2934     }
2935     xine->speed_change_flags = speed_change_flags | SPEED_FLAG_WANT_NEW;
2936     xine->speed_change_new_speed = speed;
2937     pthread_mutex_unlock (&xine->speed_change_lock);
2938     return;
2939   }
2940   xine->speed_change_flags |= SPEED_FLAG_CHANGING;
2941   pthread_mutex_unlock (&xine->speed_change_lock);
2942 
2943   while (1) {
2944     if (speed <= XINE_SPEED_PAUSE)
2945       speed = XINE_SPEED_PAUSE;
2946     xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "set_speed %d.\n", speed);
2947     set_speed_internal (stream, speed);
2948     if (stream->s.slave && (stream->slave_affection & XINE_MASTER_SLAVE_SPEED))
2949       set_speed_internal ((xine_stream_private_t *)stream->s.slave, speed);
2950 
2951     pthread_mutex_lock (&xine->speed_change_lock);
2952     speed_change_flags = xine->speed_change_flags;
2953     if (!(speed_change_flags & (SPEED_FLAG_WANT_LIVE | SPEED_FLAG_WANT_NEW))) {
2954       xine->speed_change_flags = speed_change_flags & ~(SPEED_FLAG_CHANGING | SPEED_FLAG_WANT_LIVE | SPEED_FLAG_WANT_NEW);
2955       if (speed_change_flags & SPEED_FLAG_IGNORE_CHANGE)
2956         pthread_cond_broadcast (&xine->speed_change_done);
2957       pthread_mutex_unlock (&xine->speed_change_lock);
2958       return;
2959     }
2960     if (speed_change_flags & SPEED_FLAG_WANT_LIVE) {
2961       xine->speed_change_flags = speed_change_flags & ~SPEED_FLAG_WANT_LIVE;
2962       speed = xine->speed_change_new_live;
2963     } else { /* speed_change_flags & SPEED_FLAG_WANT_NEW */
2964       xine->speed_change_flags = speed_change_flags & ~SPEED_FLAG_WANT_NEW;
2965       speed = xine->speed_change_new_speed;
2966     }
2967     pthread_mutex_unlock (&xine->speed_change_lock);
2968   }
2969 }
2970 
_x_get_fine_speed(xine_stream_t * stream)2971 int _x_get_fine_speed (xine_stream_t *stream) {
2972   return stream->xine->clock->speed;
2973 }
2974 
_x_set_speed(xine_stream_t * stream,int speed)2975 void _x_set_speed (xine_stream_t *stream, int speed) {
2976 
2977   if (speed > XINE_SPEED_FAST_4)
2978     speed = XINE_SPEED_FAST_4;
2979 
2980   _x_set_fine_speed (stream, speed * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL);
2981 }
2982 
_x_get_speed(xine_stream_t * stream)2983 int _x_get_speed (xine_stream_t *stream) {
2984   int speed = _x_get_fine_speed (stream);
2985 
2986   /*
2987    * ensure compatibility with old API, only valid XINE_SPEED_xxx
2988    * constants are allowed. XINE_SPEED_NORMAL may only be returned
2989    * if speed is exactly XINE_FINE_SPEED_NORMAL.
2990    */
2991 
2992   if( speed <= XINE_SPEED_PAUSE )
2993     return XINE_SPEED_PAUSE;
2994   if( speed <= XINE_SPEED_SLOW_4 * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL )
2995     return XINE_SPEED_SLOW_4;
2996   if( speed < XINE_FINE_SPEED_NORMAL )
2997     return XINE_SPEED_SLOW_2;
2998   if( speed == XINE_FINE_SPEED_NORMAL )
2999     return XINE_SPEED_NORMAL;
3000   if( speed <= XINE_SPEED_FAST_2 * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL )
3001     return XINE_SPEED_FAST_2;
3002   return XINE_SPEED_FAST_4;
3003 }
3004 
3005 
3006 /*
3007  * time measurement / seek
3008  */
3009 
xine_get_pos_length(xine_stream_t * s,int * pos_stream,int * pos_time,int * length_time)3010 int xine_get_pos_length (xine_stream_t *s, int *pos_stream, int *pos_time, int *length_time) {
3011   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3012   extra_info_t info;
3013   int normpos, timepos;
3014 
3015   stream = stream->side_streams[0];
3016   pthread_mutex_lock (&stream->frontend_lock);
3017 
3018   if (!stream->s.input_plugin) {
3019     lprintf ("no input source\n");
3020     pthread_mutex_unlock (&stream->frontend_lock);
3021     return 0;
3022   }
3023 
3024   if ((!stream->video_decoder_plugin && !stream->audio_decoder_plugin)) {
3025     /* rare case: no decoders available. */
3026     xine_rwlock_rdlock (&stream->info_lock);
3027     if (stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO]) {
3028       xine_rwlock_unlock (&stream->info_lock);
3029       xine_current_extra_info_set (stream, stream->video_decoder_extra_info);
3030     } else {
3031       xine_rwlock_unlock (&stream->info_lock);
3032       xine_current_extra_info_set (stream, stream->audio_decoder_extra_info);
3033     }
3034   }
3035   xine_current_extra_info_get (stream, &info);
3036   if (info.seek_count != stream->video_seek_count) {
3037     pthread_mutex_unlock (&stream->frontend_lock);
3038     return 0; /* position not yet known */
3039   }
3040   normpos = info.input_normpos;
3041   timepos = info.input_time;
3042 
3043   if (length_time) {
3044     int length = 0;
3045     /* frontend lock prevents demux unload. To be very precise, we would need to
3046      * suspend demux here as well, and trash performance :-/
3047      * Well. Demux either knows length from the start, and value is constant.
3048      * Or, it grows with current position. We can do that, too. */
3049     if (stream->demux.plugin)
3050       length = stream->demux.plugin->get_stream_length (stream->demux.plugin);
3051     pthread_mutex_unlock (&stream->frontend_lock);
3052     if ((length > 0) && (length < timepos))
3053       length = timepos;
3054     *length_time = length;
3055   } else {
3056     pthread_mutex_unlock (&stream->frontend_lock);
3057   }
3058 
3059   if (pos_stream)
3060     *pos_stream = normpos;
3061   if (pos_time)
3062     *pos_time = timepos;
3063   return 1;
3064 }
3065 
_x_get_current_frame_data(xine_stream_t * stream,xine_current_frame_data_t * data,int flags,int img_size_unknown)3066 static int _x_get_current_frame_data (xine_stream_t *stream,
3067 				      xine_current_frame_data_t *data,
3068 				      int flags, int img_size_unknown) {
3069 
3070   xine_private_t *xine;
3071   vo_frame_t *frame;
3072   size_t required_size = 0;
3073 
3074   {
3075     xine_stream_private_t *s = (xine_stream_private_t *)stream;
3076     stream = &s->side_streams[0]->s;
3077   }
3078   xine = (xine_private_t *)stream->xine;
3079 
3080   xine->port_ticket->acquire (xine->port_ticket, 1);
3081   frame = stream->video_out->get_last_frame (stream->video_out);
3082   xine->port_ticket->release (xine->port_ticket, 1);
3083 
3084   if (!frame) {
3085     data->img_size = 0;
3086     return 0;
3087   }
3088 
3089   data->width       = frame->width;
3090   data->height      = frame->height;
3091   data->crop_left   = frame->crop_left;
3092   data->crop_right  = frame->crop_right;
3093   data->crop_top    = frame->crop_top;
3094   data->crop_bottom = frame->crop_bottom;
3095 
3096   data->ratio_code = 10000.0 * frame->ratio;
3097   /* make ratio_code backward compatible */
3098 #define RATIO_LIKE(a, b)  ((b) - 1 <= (a) && (a) <= 1 + (b))
3099   if (RATIO_LIKE(data->ratio_code, 10000))
3100     data->ratio_code = XINE_VO_ASPECT_SQUARE;
3101   else if (RATIO_LIKE(data->ratio_code, 13333))
3102     data->ratio_code = XINE_VO_ASPECT_4_3;
3103   else if (RATIO_LIKE(data->ratio_code, 17778))
3104     data->ratio_code = XINE_VO_ASPECT_ANAMORPHIC;
3105   else if (RATIO_LIKE(data->ratio_code, 21100))
3106     data->ratio_code = XINE_VO_ASPECT_DVB;
3107 
3108   data->format     = frame->format;
3109   data->interlaced = frame->progressive_frame ? 0 : (2 - frame->top_field_first);
3110 
3111   switch (frame->format) {
3112 
3113   default:
3114     if (frame->proc_provide_standard_frame_data) {
3115       uint8_t *img = data->img;
3116       size_t img_size = data->img_size;
3117       data->img = 0;
3118       data->img_size = 0;
3119 
3120       /* ask frame implementation for required img buffer size */
3121       frame->proc_provide_standard_frame_data(frame, data);
3122       required_size = data->img_size;
3123 
3124       data->img = img;
3125       data->img_size = img_size;
3126       break;
3127     }
3128 
3129     if (!data->img && !(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
3130       break; /* not interested in image data */
3131 
3132     xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
3133 	     "xine: error, snapshot function not implemented for format 0x%x\n", frame->format);
3134     /* fall through and provide "green" YV12 image */
3135     data->format = XINE_IMGFMT_YV12;
3136     /* fall through */
3137   case XINE_IMGFMT_YV12:
3138     required_size = frame->width * frame->height
3139                   + ((frame->width + 1) / 2) * ((frame->height + 1) / 2)
3140                   + ((frame->width + 1) / 2) * ((frame->height + 1) / 2);
3141     break;
3142 
3143   case XINE_IMGFMT_YUY2:
3144     required_size = frame->width * frame->height
3145                   + ((frame->width + 1) / 2) * frame->height
3146                   + ((frame->width + 1) / 2) * frame->height;
3147     break;
3148 
3149   }
3150 
3151   if (flags & XINE_FRAME_DATA_ALLOCATE_IMG) {
3152     /* return allocated buffer size */
3153     data->img_size = required_size;
3154     /* allocate img or fail */
3155     if (!(data->img = calloc(1, required_size))) {
3156       frame->free(frame);
3157       return 0;
3158     }
3159   } else {
3160     /* fail if supplied buffer is to small */
3161     if (data->img && !img_size_unknown && data->img_size < (int)required_size) {
3162       data->img_size = required_size;
3163       frame->free(frame);
3164       return 0;
3165     }
3166     /* return used buffer size */
3167     data->img_size = required_size;
3168   }
3169 
3170   if (data->img) {
3171     switch (frame->format) {
3172 
3173     case XINE_IMGFMT_YV12:
3174       yv12_to_yv12(
3175        /* Y */
3176         frame->base[0], frame->pitches[0],
3177         data->img, frame->width,
3178        /* U */
3179         frame->base[1], frame->pitches[1],
3180         data->img+frame->width*frame->height, frame->width/2,
3181        /* V */
3182         frame->base[2], frame->pitches[2],
3183         data->img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2,
3184        /* width x height */
3185         frame->width, frame->height);
3186       break;
3187 
3188     case XINE_IMGFMT_YUY2:
3189       yuy2_to_yuy2(
3190        /* src */
3191         frame->base[0], frame->pitches[0],
3192        /* dst */
3193         data->img, frame->width*2,
3194        /* width x height */
3195         frame->width, frame->height);
3196       break;
3197 
3198     default:
3199       if (frame->proc_provide_standard_frame_data)
3200         frame->proc_provide_standard_frame_data(frame, data);
3201       else if (!(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
3202         memset(data->img, 0, data->img_size);
3203     }
3204   }
3205 
3206   frame->free(frame);
3207   return 1;
3208 }
3209 
xine_get_current_frame_data(xine_stream_t * stream,xine_current_frame_data_t * data,int flags)3210 int xine_get_current_frame_data (xine_stream_t *stream,
3211 				 xine_current_frame_data_t *data,
3212 				 int flags) {
3213 
3214   return _x_get_current_frame_data(stream, data, flags, 0);
3215 }
3216 
xine_get_current_frame_alloc(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t ** img,int * img_size)3217 int xine_get_current_frame_alloc (xine_stream_t *stream, int *width, int *height,
3218 				  int *ratio_code, int *format,
3219 				  uint8_t **img, int *img_size) {
3220 
3221   int result;
3222   xine_current_frame_data_t data;
3223 
3224   memset(&data, 0, sizeof (data));
3225 
3226   result = _x_get_current_frame_data(stream, &data, img ? XINE_FRAME_DATA_ALLOCATE_IMG : 0, 0);
3227   if (width)      *width      = data.width;
3228   if (height)     *height     = data.height;
3229   if (ratio_code) *ratio_code = data.ratio_code;
3230   if (format)     *format     = data.format;
3231   if (img_size)   *img_size   = data.img_size;
3232   if (img)        *img        = data.img;
3233   return result;
3234 }
3235 
xine_get_current_frame_s(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t * img,int * img_size)3236 int xine_get_current_frame_s (xine_stream_t *stream, int *width, int *height,
3237 				int *ratio_code, int *format,
3238 				uint8_t *img, int *img_size) {
3239   int result;
3240   xine_current_frame_data_t data;
3241 
3242   memset(&data, 0, sizeof (data));
3243   data.img = img;
3244   if (img_size)
3245     data.img_size = *img_size;
3246 
3247   result = _x_get_current_frame_data(stream, &data, 0, 0);
3248   if (width)      *width      = data.width;
3249   if (height)     *height     = data.height;
3250   if (ratio_code) *ratio_code = data.ratio_code;
3251   if (format)     *format     = data.format;
3252   if (img_size)   *img_size   = data.img_size;
3253   return result;
3254 }
3255 
xine_get_current_frame(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t * img)3256 int xine_get_current_frame (xine_stream_t *stream, int *width, int *height,
3257 			    int *ratio_code, int *format,
3258 			    uint8_t *img) {
3259   int result;
3260   xine_current_frame_data_t data;
3261 
3262   memset(&data, 0, sizeof (data));
3263   data.img = img;
3264 
3265   result = _x_get_current_frame_data(stream, &data, 0, 1);
3266   if (width)      *width      = data.width;
3267   if (height)     *height     = data.height;
3268   if (ratio_code) *ratio_code = data.ratio_code;
3269   if (format)     *format     = data.format;
3270   return result;
3271 }
3272 
xine_new_grab_video_frame(xine_stream_t * stream)3273 xine_grab_video_frame_t* xine_new_grab_video_frame (xine_stream_t *stream) {
3274   xine_private_t *xine = (xine_private_t *)stream->xine;
3275   xine_grab_video_frame_t *frame;
3276 
3277   xine->port_ticket->acquire (xine->port_ticket, 1);
3278 
3279   {
3280     xine_stream_private_t *s = (xine_stream_private_t *)stream;
3281     stream = &s->side_streams[0]->s;
3282   }
3283 
3284   if (stream->video_out->driver->new_grab_video_frame)
3285     frame = stream->video_out->driver->new_grab_video_frame(stream->video_out->driver);
3286   else
3287     frame = stream->video_out->new_grab_video_frame(stream->video_out);
3288 
3289   xine->port_ticket->release (xine->port_ticket, 1);
3290 
3291   return frame;
3292 }
3293 
_get_spu_lang(xine_stream_private_t * stream,int channel,char * lang)3294 static int _get_spu_lang (xine_stream_private_t *stream, int channel, char *lang) {
3295   if (!lang)
3296     return 0;
3297 
3298   /* Ask the demuxer first (e.g. TS extracts this information from
3299    * the stream)
3300    **/
3301   if (stream->demux.plugin) {
3302     if (stream->demux.plugin->get_capabilities (stream->demux.plugin) & DEMUX_CAP_SPULANG) {
3303       /* pass the channel number to the plugin in the data field */
3304       memcpy(lang, &channel, sizeof(channel));
3305       if (stream->demux.plugin->get_optional_data (stream->demux.plugin, lang,
3306 	  DEMUX_OPTIONAL_DATA_SPULANG) == DEMUX_OPTIONAL_SUCCESS)
3307         return 1;
3308     }
3309   }
3310 
3311   /* No match, check with input plugin instead (e.g. DVD gets this
3312    * info from the IFO).
3313    **/
3314   if (stream->s.input_plugin) {
3315     if (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_SPULANG) {
3316       /* pass the channel number to the plugin in the data field */
3317       memcpy(lang, &channel, sizeof(channel));
3318       if (stream->s.input_plugin->get_optional_data (stream->s.input_plugin, lang,
3319 	  INPUT_OPTIONAL_DATA_SPULANG) == INPUT_OPTIONAL_SUCCESS)
3320         return 1;
3321     }
3322   }
3323 
3324   memcpy (lang, "und", 4);
3325   return 0;
3326 }
3327 
xine_get_spu_lang(xine_stream_t * s,int channel,char * lang)3328 int xine_get_spu_lang (xine_stream_t *s, int channel, char *lang) {
3329   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3330   int ret;
3331 
3332   pthread_mutex_lock (&stream->frontend_lock);
3333   ret = _get_spu_lang(stream, channel, lang);
3334   pthread_mutex_unlock (&stream->frontend_lock);
3335   return ret;
3336 }
3337 
_get_audio_lang(xine_stream_private_t * stream,int channel,char * lang)3338 static int _get_audio_lang (xine_stream_private_t *stream, int channel, char *lang) {
3339   if (!lang)
3340     return 0;
3341 
3342   if (stream->demux.plugin) {
3343     if (stream->demux.plugin->get_capabilities (stream->demux.plugin) & DEMUX_CAP_AUDIOLANG) {
3344       /* pass the channel number to the plugin in the data field */
3345       memcpy(lang, &channel, sizeof(channel));
3346       if (stream->demux.plugin->get_optional_data (stream->demux.plugin, lang,
3347 	  DEMUX_OPTIONAL_DATA_AUDIOLANG) == DEMUX_OPTIONAL_SUCCESS)
3348         return 1;
3349     }
3350   }
3351 
3352   if (stream->s.input_plugin) {
3353     if (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_AUDIOLANG) {
3354       /* pass the channel number to the plugin in the data field */
3355       memcpy(lang, &channel, sizeof(channel));
3356       if (stream->s.input_plugin->get_optional_data (stream->s.input_plugin, lang,
3357 	  INPUT_OPTIONAL_DATA_AUDIOLANG) == INPUT_OPTIONAL_SUCCESS)
3358         return 1;
3359     }
3360   }
3361 
3362   memcpy (lang, "und", 4);
3363   return 0;
3364 }
3365 
xine_get_audio_lang(xine_stream_t * s,int channel,char * lang)3366 int xine_get_audio_lang (xine_stream_t *s, int channel, char *lang) {
3367   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3368   int ret;
3369 
3370   pthread_mutex_lock (&stream->frontend_lock);
3371   ret = _get_audio_lang(stream, channel, lang);
3372   pthread_mutex_unlock (&stream->frontend_lock);
3373   return ret;
3374 }
3375 
_x_get_spu_channel(xine_stream_t * stream)3376 int _x_get_spu_channel (xine_stream_t *stream) {
3377   xine_stream_private_t *s = (xine_stream_private_t *)stream;
3378   stream = &s->side_streams[0]->s;
3379   return stream->spu_channel_user;
3380 }
3381 
_x_get_video_streamtype(xine_stream_t * s)3382 int _x_get_video_streamtype (xine_stream_t *s) {
3383   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3384   stream = stream->side_streams[0];
3385   return stream->video_decoder_streamtype;
3386 }
3387 
3388 /*
3389  * log functions
3390  */
xine_get_log_section_count(xine_t * this)3391 int xine_get_log_section_count (xine_t *this) {
3392   (void)this;
3393   return XINE_LOG_NUM;
3394 }
3395 
xine_get_log_names(xine_t * this)3396 const char *const *xine_get_log_names (xine_t *this) {
3397   static const char *log_sections[XINE_LOG_NUM + 1];
3398 
3399   log_sections[XINE_LOG_MSG]      = _("messages");
3400   log_sections[XINE_LOG_PLUGIN]   = _("plugin");
3401   log_sections[XINE_LOG_TRACE]    = _("trace");
3402   log_sections[XINE_LOG_NUM]      = NULL;
3403 
3404   (void)this;
3405   return log_sections;
3406 }
3407 
check_log_alloc(xine_private_t * this,int buf)3408 static inline void check_log_alloc (xine_private_t *this, int buf)
3409 {
3410   if (this->x.log_buffers[buf])
3411     return;
3412 
3413   pthread_mutex_lock (&this->log_lock);
3414 
3415   if (!this->x.log_buffers[buf])
3416     this->x.log_buffers[buf] = _x_new_scratch_buffer(150);
3417 
3418   pthread_mutex_unlock (&this->log_lock);
3419 }
3420 
xine_log(xine_t * this_gen,int buf,const char * format,...)3421 void xine_log (xine_t *this_gen, int buf, const char *format, ...) {
3422   xine_private_t *this = (xine_private_t *)this_gen;
3423   va_list argp;
3424   char    buffer[SCRATCH_LINE_LEN_MAX];
3425 
3426   check_log_alloc (this, buf);
3427 
3428   va_start (argp, format);
3429   this->x.log_buffers[buf]->scratch_printf (this->x.log_buffers[buf], format, argp);
3430   va_end(argp);
3431 
3432   if (this->x.verbosity) {
3433     va_start(argp, format);
3434     vsnprintf(buffer, SCRATCH_LINE_LEN_MAX, format, argp);
3435     printf("%s", buffer);
3436     va_end (argp);
3437   }
3438 
3439   if (this->log_cb)
3440     this->log_cb (this->log_cb_user_data, buf);
3441 }
3442 
xine_vlog(xine_t * this_gen,int buf,const char * format,va_list args)3443 void xine_vlog (xine_t *this_gen, int buf, const char *format,
3444                 va_list args)
3445 {
3446   xine_private_t *this = (xine_private_t *)this_gen;
3447   check_log_alloc (this, buf);
3448 
3449   this->x.log_buffers[buf]->scratch_printf (this->x.log_buffers[buf], format, args);
3450 
3451   if (this->log_cb)
3452     this->log_cb (this->log_cb_user_data, buf);
3453 }
3454 
xine_get_log(xine_t * this,int buf)3455 char *const *xine_get_log (xine_t *this, int buf) {
3456 
3457   if(buf >= XINE_LOG_NUM)
3458     return NULL;
3459 
3460   if ( this->log_buffers[buf] )
3461     return this->log_buffers[buf]->get_content (this->log_buffers[buf]);
3462   else
3463     return NULL;
3464 }
3465 
xine_register_log_cb(xine_t * this_gen,xine_log_cb_t cb,void * user_data)3466 void xine_register_log_cb (xine_t *this_gen, xine_log_cb_t cb, void *user_data) {
3467   xine_private_t *this = (xine_private_t *)this_gen;
3468   this->log_cb = cb;
3469   this->log_cb_user_data = user_data;
3470 }
3471 
xine_get_error(xine_stream_t * s)3472 int xine_get_error (xine_stream_t *s) {
3473   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3474   stream = stream->side_streams[0];
3475   return stream->err;
3476 }
3477 
xine_stream_master_slave(xine_stream_t * m,xine_stream_t * slave,int affection)3478 int xine_stream_master_slave (xine_stream_t *m, xine_stream_t *slave, int affection) {
3479   xine_stream_private_t *master = (xine_stream_private_t *)m;
3480   master->s.slave = slave;
3481   master->slave_affection = affection;
3482   /* respect transitivity: if our designated master already has a master
3483    * of its own, we point to this master's master; if our master is a
3484    * standalone stream, its master pointer will point to itself */
3485   slave->master = master->s.master;
3486 
3487   _x_select_spu_channel (m, master->s.spu_channel_user);
3488   return 1;
3489 }
3490 
_x_query_buffer_usage(xine_stream_t * stream,int * num_video_buffers,int * num_audio_buffers,int * num_video_frames,int * num_audio_frames)3491 int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames)
3492 {
3493   xine_private_t *xine = (xine_private_t *)stream->xine;
3494   int ticket_acquired = -1;
3495 
3496   {
3497     xine_stream_private_t *s = (xine_stream_private_t *)stream;
3498     stream = &s->side_streams[0]->s;
3499   }
3500 
3501   if (num_video_buffers)
3502     *num_video_buffers = (stream->video_fifo ? stream->video_fifo->size(stream->video_fifo) : 0);
3503 
3504   if (num_audio_buffers)
3505     *num_audio_buffers = (stream->audio_fifo ? stream->audio_fifo->size(stream->audio_fifo) : 0);
3506 
3507   if ((num_video_frames && stream->video_out)
3508     || (num_audio_frames && stream->audio_out)) {
3509 
3510     ticket_acquired = xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1);
3511   }
3512 
3513   if (num_video_frames)
3514     *num_video_frames = ((ticket_acquired && stream->video_out) ? stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO) : 0);
3515 
3516   if (num_audio_frames)
3517     *num_audio_frames = ((ticket_acquired && stream->audio_out) ? stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO) : 0);
3518 
3519   if (ticket_acquired > 0)
3520     xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3521 
3522   return ticket_acquired != 0;
3523 }
3524 
_x_query_buffers_fix_data(xine_query_buffers_data_t * data)3525 static void _x_query_buffers_fix_data(xine_query_buffers_data_t *data)
3526 {
3527   if (data->total < 0)
3528     data->total = 0;
3529 
3530   if (data->ready < 0)
3531     data->ready = 0;
3532 
3533   if (data->avail < 0)
3534     data->avail = 0;
3535 
3536   /* fix race condition of not filling data atomically */
3537   if (data->ready + data->avail > data->total)
3538     data->avail = data->total - data->ready;
3539 }
3540 
_x_query_buffers(xine_stream_t * stream,xine_query_buffers_t * query)3541 int _x_query_buffers(xine_stream_t *stream, xine_query_buffers_t *query)
3542 {
3543   xine_private_t *xine = (xine_private_t *)stream->xine;
3544   int ticket_acquired = -1;
3545 
3546   {
3547     xine_stream_private_t *s = (xine_stream_private_t *)stream;
3548     stream = &s->side_streams[0]->s;
3549   }
3550 
3551   memset(query, 0, sizeof (*query));
3552 
3553   if (stream->video_fifo)
3554   {
3555     query->vi.total = stream->video_fifo->buffer_pool_capacity;
3556     query->vi.ready = stream->video_fifo->size(stream->video_fifo);
3557     query->vi.avail = stream->video_fifo->num_free(stream->video_fifo);
3558     _x_query_buffers_fix_data(&query->vi);
3559   }
3560 
3561   if (stream->audio_fifo)
3562   {
3563     query->ai.total = stream->audio_fifo->buffer_pool_capacity;
3564     query->ai.ready = stream->audio_fifo->size(stream->audio_fifo);
3565     query->ai.avail = stream->audio_fifo->num_free(stream->audio_fifo);
3566     _x_query_buffers_fix_data(&query->ai);
3567   }
3568 
3569   if (stream->video_out || stream->audio_out)
3570     ticket_acquired = xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1);
3571 
3572   if (ticket_acquired > 0)
3573   {
3574     if (stream->video_out)
3575     {
3576       query->vo.total = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_TOTAL);
3577       query->vo.ready = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO);
3578       query->vo.avail = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_FREE);
3579     }
3580 
3581     if (stream->audio_out)
3582     {
3583       query->ao.total = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_TOTAL);
3584       query->ao.ready = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO);
3585       query->ao.avail = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_FREE);
3586     }
3587 
3588     xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3589   }
3590 
3591   return ticket_acquired != 0;
3592 }
3593 
_x_lock_port_rewiring(xine_t * xine_gen,int ms_timeout)3594 int _x_lock_port_rewiring (xine_t *xine_gen, int ms_timeout)
3595 {
3596   xine_private_t *xine = (xine_private_t *)xine_gen;
3597   return xine->port_ticket->lock_port_rewiring(xine->port_ticket, ms_timeout);
3598 }
3599 
_x_unlock_port_rewiring(xine_t * xine_gen)3600 void _x_unlock_port_rewiring (xine_t *xine_gen)
3601 {
3602   xine_private_t *xine = (xine_private_t *)xine_gen;
3603   xine->port_ticket->unlock_port_rewiring(xine->port_ticket);
3604 }
3605 
_x_lock_frontend(xine_stream_t * s,int ms_to_time_out)3606 int _x_lock_frontend (xine_stream_t *s, int ms_to_time_out) {
3607   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3608   stream = stream->side_streams[0];
3609   return lock_timeout (&stream->frontend_lock, ms_to_time_out);
3610 }
3611 
_x_unlock_frontend(xine_stream_t * s)3612 void _x_unlock_frontend (xine_stream_t *s) {
3613   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3614   stream = stream->side_streams[0];
3615   pthread_mutex_unlock(&stream->frontend_lock);
3616 }
3617 
_x_query_unprocessed_osd_events(xine_stream_t * stream)3618 int _x_query_unprocessed_osd_events(xine_stream_t *stream)
3619 {
3620   xine_private_t *xine = (xine_private_t *)stream->xine;
3621   video_overlay_manager_t *ovl;
3622   int redraw_needed;
3623 
3624   {
3625     xine_stream_private_t *s = (xine_stream_private_t *)stream;
3626     stream = &s->side_streams[0]->s;
3627   }
3628 
3629   if (!xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1))
3630     return -1;
3631 
3632   ovl = stream->video_out->get_overlay_manager(stream->video_out);
3633   redraw_needed = ovl->redraw_needed(ovl, 0);
3634 
3635   if (redraw_needed)
3636     stream->video_out->trigger_drawing(stream->video_out);
3637 
3638   xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3639 
3640   return redraw_needed;
3641 }
3642 
_x_continue_stream_processing(xine_stream_t * s)3643 int _x_continue_stream_processing (xine_stream_t *s) {
3644   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3645   stream = stream->side_streams[0];
3646   return stream->status != XINE_STATUS_STOP
3647     && stream->status != XINE_STATUS_QUIT;
3648 }
3649 
_x_trigger_relaxed_frame_drop_mode(xine_stream_t * s)3650 void _x_trigger_relaxed_frame_drop_mode (xine_stream_t *s) {
3651   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3652   stream = stream->side_streams[0];
3653   pthread_mutex_lock (&stream->first_frame.lock);
3654   stream->first_frame.flag = 2;
3655   pthread_mutex_unlock (&stream->first_frame.lock);
3656 }
3657 
_x_reset_relaxed_frame_drop_mode(xine_stream_t * s)3658 void _x_reset_relaxed_frame_drop_mode (xine_stream_t *s) {
3659   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3660   stream = stream->side_streams[0];
3661   pthread_mutex_lock (&stream->first_frame.lock);
3662   stream->first_frame.flag = 1;
3663   pthread_mutex_unlock (&stream->first_frame.lock);
3664 }
3665 
3666 
3667 #define KF_BITS 10
3668 #define KF_SIZE (1 << KF_BITS)
3669 #define KF_MASK (KF_SIZE - 1)
3670 
xine_keyframes_find(xine_stream_t * s,xine_keyframes_entry_t * pos,int offs)3671 int xine_keyframes_find (xine_stream_t *s, xine_keyframes_entry_t *pos, int offs) {
3672   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3673   if (!stream || (&stream->s == XINE_ANON_STREAM) || !pos)
3674     return 2;
3675 
3676   stream = stream->side_streams[0];
3677   pthread_mutex_lock (&stream->index.lock);
3678   if (!stream->index.array || !stream->index.used) {
3679     pthread_mutex_unlock (&stream->index.lock);
3680     return 2;
3681   }
3682   /* binary search the index */
3683   {
3684     xine_keyframes_entry_t *t = stream->index.array;
3685     int d, a = 0, e = stream->index.used, m = e >> 1, l;
3686     if ((pos->normpos > 0) && (pos->normpos < 0x10000)) {
3687       do {
3688         d = t[m].normpos - pos->normpos;
3689         if (d == 0)
3690           break;
3691         if (d > 0)
3692           e = m;
3693         else
3694           a = m;
3695         l = m;
3696         m = (a + e) >> 1;
3697       } while (m != l);
3698       if ((offs == 0) && (m + 1 < stream->index.used) &&
3699         (pos->normpos >= ((t[m].normpos + t[m + 1].normpos) >> 1)))
3700         m++;
3701     } else {
3702       do {
3703         d = t[m].msecs - pos->msecs;
3704         if (d == 0)
3705           break;
3706         if (d > 0)
3707           e = m;
3708         else
3709           a = m;
3710         l = m;
3711         m = (a + e) >> 1;
3712       } while (m != l);
3713       if ((offs == 0) && (m + 1 < stream->index.used) &&
3714         (pos->msecs >= ((t[m].msecs + t[m + 1].msecs) >> 1)))
3715         m++;
3716     }
3717     e = 0;
3718     if ((offs < 0) && (d != 0))
3719       offs++;
3720     m += offs;
3721     if (m < 0) {
3722       m = 0;
3723       e = 1;
3724     } else if (m >= stream->index.used) {
3725       m = stream->index.used - 1;
3726       e = 1;
3727     }
3728     *pos = t[m];
3729     pthread_mutex_unlock (&stream->index.lock);
3730     return e;
3731   }
3732 }
3733 
_x_keyframes_add(xine_stream_t * s,xine_keyframes_entry_t * pos)3734 int _x_keyframes_add (xine_stream_t *s, xine_keyframes_entry_t *pos) {
3735   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3736   xine_keyframes_entry_t *t;
3737   stream = stream->side_streams[0];
3738   pthread_mutex_lock (&stream->index.lock);
3739   /* first ever entry */
3740   t = stream->index.array;
3741   if (!t) {
3742     t = calloc (KF_SIZE, sizeof (*t));
3743     if (!t) {
3744       pthread_mutex_unlock (&stream->index.lock);
3745       return -1;
3746     }
3747     t[0] = *pos;
3748     stream->index.array = t;
3749     stream->index.lastadd = 0;
3750     stream->index.used = 1;
3751     stream->index.size = KF_SIZE;
3752     pthread_mutex_unlock (&stream->index.lock);
3753     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3754       "keyframes: build index while playing.\n");
3755     return 0;
3756   }
3757   /* enlarge buf */
3758   if (stream->index.used + 1 >= stream->index.size) {
3759     t = realloc (stream->index.array, (stream->index.size + KF_SIZE) * sizeof (*t));
3760     if (!t) {
3761       pthread_mutex_unlock (&stream->index.lock);
3762       return -1;
3763     }
3764     stream->index.array = t;
3765     stream->index.size += KF_SIZE;
3766   }
3767   /* binary search seek target */
3768   {
3769     /* fast detect the most common "progressive" case */
3770     int d, a = 0, m = stream->index.lastadd, l, e = stream->index.used;
3771     if (m + 1 < e)
3772       m++;
3773     do {
3774       d = t[m].msecs - pos->msecs;
3775       if (abs (d) < 10) {
3776         t[m] = *pos; /* already known */
3777         pthread_mutex_unlock (&stream->index.lock);
3778         return m;
3779       }
3780       if (d > 0)
3781         e = m;
3782       else
3783         a = m;
3784       l = m;
3785       m = (a + e) >> 1;
3786     } while (m != l);
3787     if (d < 0)
3788       m++;
3789     if (m < stream->index.used) /* insert */
3790       memmove (&t[m + 1], &t[m], (stream->index.used - m) * sizeof (*t));
3791     stream->index.used++;
3792     stream->index.lastadd = m;
3793     t[m] = *pos;
3794     pthread_mutex_unlock (&stream->index.lock);
3795     return m;
3796   }
3797 }
3798 
xine_keyframes_get(xine_stream_t * s,int * size)3799 xine_keyframes_entry_t *xine_keyframes_get (xine_stream_t *s, int *size) {
3800   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3801   xine_keyframes_entry_t *ret;
3802   if (!stream || (&stream->s == XINE_ANON_STREAM) || !size)
3803     return NULL;
3804   stream = stream->side_streams[0];
3805   pthread_mutex_lock (&stream->index.lock);
3806   if (stream->index.array && stream->index.used) {
3807     ret = malloc (stream->index.used * sizeof (xine_keyframes_entry_t));
3808     if (ret) {
3809       memcpy (ret, stream->index.array, stream->index.used * sizeof (xine_keyframes_entry_t));
3810       *size = stream->index.used;
3811     }
3812   } else {
3813     ret = NULL;
3814     *size = 0;
3815   }
3816   pthread_mutex_unlock (&stream->index.lock);
3817   return ret;
3818 }
3819 
_x_keyframes_set(xine_stream_t * s,xine_keyframes_entry_t * list,int size)3820 int _x_keyframes_set (xine_stream_t *s, xine_keyframes_entry_t *list, int size) {
3821   xine_stream_private_t *stream = (xine_stream_private_t *)s;
3822   int n = (size + KF_MASK) & ~KF_MASK;
3823   stream = stream->side_streams[0];
3824   pthread_mutex_lock (&stream->index.lock);
3825   if (stream->index.array) {
3826     xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3827       "keyframes: deleting index.\n");
3828     free (stream->index.array);
3829   }
3830   stream->index.lastadd = 0;
3831   stream->index.array = (list && (n > 0)) ? malloc (n * sizeof (xine_keyframes_entry_t)) : NULL;
3832   if (!stream->index.array) {
3833     stream->index.used = 0;
3834     stream->index.size = 0;
3835     pthread_mutex_unlock (&stream->index.lock);
3836     return 1;
3837   }
3838   memcpy (stream->index.array, list, size * sizeof (xine_keyframes_entry_t));
3839   stream->index.used = size;
3840   stream->index.size = n;
3841   n -= size;
3842   if (n > 0)
3843     memset (stream->index.array + size, 0, n * sizeof (xine_keyframes_entry_t));
3844   pthread_mutex_unlock (&stream->index.lock);
3845   xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3846     "keyframes: got %d of them.\n", stream->index.used);
3847   return 0;
3848 }
3849